diff --git a/.github/workflows/gobra.yml b/.github/workflows/gobra.yml index 394f12c15..60af6ae6c 100644 --- a/.github/workflows/gobra.yml +++ b/.github/workflows/gobra.yml @@ -46,7 +46,7 @@ jobs: recursive: 1 ## Due to a bug, we cannot use the recursive mode with friend pacakge invariants. excludePackages: 'layers' - timeout: 5m + timeout: 10m headerOnly: ${{ env.headerOnly }} module: ${{ env.module }} includePaths: './dependencies/ ..' # relative to project location @@ -321,7 +321,9 @@ jobs: uses: viperproject/gobra-action@main with: packages: 'pkg/slayers/path/scion' - timeout: 30m + # timeout raised while the seq-based proofs are tuned; the goal is + # to bring it back to 30m once the annotations are streamlined + timeout: 45m headerOnly: ${{ env.headerOnly }} module: ${{ env.module }} includePaths: ${{ env.includePaths }} diff --git a/pkg/experimental/epic/epic.go b/pkg/experimental/epic/epic.go index e4f0bf8ca..876a3d20c 100644 --- a/pkg/experimental/epic/epic.go +++ b/pkg/experimental/epic/epic.go @@ -148,8 +148,8 @@ func CalcMac(auth []byte, pktID epic.PktID, s *slayers.SCION, // @ package (sl.Bytes(result, 0, len(result)) --* sl.Bytes(oldBuffer, 0, len(oldBuffer))) { // @ ghost if !allocatesNewBuffer { // @ assert oldBuffer === buffer - // @ sl.CombineRange_Bytes(input, start, end, writePerm) - // @ sl.CombineRange_Bytes(oldBuffer, 0, inputLength, writePerm) + // @ sl.CombineRangeNoView_Bytes(input, start, end, writePerm) + // @ sl.CombineRangeNoView_Bytes(oldBuffer, 0, inputLength, writePerm) // @ } // @ } // @ assert (sl.Bytes(result, 0, len(result)) --* sl.Bytes(oldBuffer, 0, len(oldBuffer))) diff --git a/pkg/slayers/path/hopfield.go b/pkg/slayers/path/hopfield.go index 03299dbb4..3cb587b30 100644 --- a/pkg/slayers/path/hopfield.go +++ b/pkg/slayers/path/hopfield.go @@ -79,13 +79,15 @@ type HopField struct { // @ preserves acc(sl.Bytes(raw, 0, HopLen), R45) // @ ensures h.Mem() // @ ensures err == nil -// @ ensures BytesToIO_HF(raw, 0, 0, HopLen) == +// @ ensures BytesToIO_HF(sl.View(raw, 0, HopLen)) == // @ unfolding acc(h.Mem(), R10) in h.Abs() // @ decreases func (h *HopField) DecodeFromBytes(raw []byte) (err error) { if len(raw) < HopLen { return serrors.New("HopField raw too short", "expected", HopLen, "actual", len(raw)) } + //@ ghost v := sl.View(raw, 0, HopLen) + //@ sl.ViewElems(raw, 0, HopLen, R46) //@ unfold acc(sl.Bytes(raw, 0, HopLen), R46) h.EgressRouterAlert = raw[0]&0x1 == 0x1 h.IngressRouterAlert = raw[0]&0x2 == 0x2 @@ -100,8 +102,14 @@ func (h *HopField) DecodeFromBytes(raw []byte) (err error) { copy(h.Mac[:], raw[6:6+MacLen] /*@ , R47 @*/) //@ assert forall i int :: {&h.Mac[:][i]} 0 <= i && i < MacLen ==> h.Mac[:][i] == raw[6:6+MacLen][i] //@ assert forall i int :: {&h.Mac[i]} 0 <= i && i < MacLen ==> h.Mac[:][i] == h.Mac[i] - //@ EqualBytesImplyEqualMac(raw[6:6+MacLen], h.Mac) - //@ assert BytesToIO_HF(raw, 0, 0, HopLen) == h.Abs() + //@ assert v[2] == raw[2] && v[3] == raw[3] && v[4] == raw[4] && v[5] == raw[5] + //@ assert forall i int :: { v[6:6+MacLen][i] } 0 <= i && i < MacLen ==> + //@ v[6:6+MacLen][i] == v[6+i] + //@ assert forall i int :: { &raw[6+i] } 0 <= i && i < MacLen ==> v[6+i] == raw[6+i] + //@ assert forall i int :: { h.Mac[i] } 0 <= i && i < MacLen ==> + //@ v[6:6+MacLen][i] == h.Mac[i] + //@ EqualSeqImplyEqualMac(v[6:6+MacLen], h.Mac) + //@ assert BytesToIO_HF(v) == h.Abs() //@ fold acc(sl.Bytes(raw, 0, HopLen), R46) //@ fold h.Mem() return nil @@ -113,7 +121,7 @@ func (h *HopField) DecodeFromBytes(raw []byte) (err error) { // @ preserves acc(h.Mem(), R10) // @ preserves sl.Bytes(b, 0, HopLen) // @ ensures err == nil -// @ ensures BytesToIO_HF(b, 0, 0, HopLen) == +// @ ensures BytesToIO_HF(sl.View(b, 0, HopLen)) == // @ unfolding acc(h.Mem(), R10) in h.Abs() // @ decreases func (h *HopField) SerializeTo(b []byte) (err error) { @@ -134,6 +142,8 @@ func (h *HopField) SerializeTo(b []byte) (err error) { binary.BigEndian.PutUint16(b[2:4], h.ConsIngress) //@ assert &b[4:6][0] == &b[4] && &b[4:6][1] == &b[5] binary.BigEndian.PutUint16(b[4:6], h.ConsEgress) + //@ assert binary.BigEndian.Uint16Spec(b[2], b[3]) == h.ConsIngress + //@ assert binary.BigEndian.Uint16Spec(b[4], b[5]) == h.ConsEgress //@ assert forall i int :: { &b[i] } 0 <= i && i < HopLen ==> acc(&b[i]) //@ assert forall i int :: { &h.Mac[:][i] } 0 <= i && i < len(h.Mac) ==> //@ &h.Mac[i] == &h.Mac[:][i] @@ -141,9 +151,34 @@ func (h *HopField) SerializeTo(b []byte) (err error) { copy(b[6:6+MacLen], h.Mac[:] /*@, R47 @*/) //@ assert forall i int :: {&h.Mac[:][i]} 0 <= i && i < MacLen ==> h.Mac[:][i] == b[6:6+MacLen][i] //@ assert forall i int :: {&h.Mac[i]} 0 <= i && i < MacLen ==> h.Mac[:][i] == h.Mac[i] - //@ EqualBytesImplyEqualMac(b[6:6+MacLen], h.Mac) + //@ assert forall i int :: { &b[6+i] } 0 <= i && i < MacLen ==> b[6:6+MacLen][i] == b[6+i] + //@ ghost b2 := b[2] + //@ ghost b3 := b[3] + //@ ghost b4 := b[4] + //@ ghost b5 := b[5] + //@ ghost mac := seq[byte]{b[6], b[7], b[8], b[9], b[10], b[11]} + //@ assert forall i int :: { mac[i] } 0 <= i && i < MacLen ==> mac[i] == h.Mac[i] //@ fold sl.Bytes(b, 0, HopLen) - //@ assert h.Abs() == BytesToIO_HF(b, 0, 0, HopLen) + // the GetByte terms instantiate the preservation postconditions of + // ViewElems, which carry the byte values across the lemma call + //@ assert sl.GetByte(b, 0, HopLen, 2) == b2 && sl.GetByte(b, 0, HopLen, 3) == b3 + //@ assert sl.GetByte(b, 0, HopLen, 4) == b4 && sl.GetByte(b, 0, HopLen, 5) == b5 + //@ assert sl.GetByte(b, 0, HopLen, 6) == mac[0] && sl.GetByte(b, 0, HopLen, 7) == mac[1] + //@ assert sl.GetByte(b, 0, HopLen, 8) == mac[2] && sl.GetByte(b, 0, HopLen, 9) == mac[3] + //@ assert sl.GetByte(b, 0, HopLen, 10) == mac[4] && sl.GetByte(b, 0, HopLen, 11) == mac[5] + //@ sl.ViewElems(b, 0, HopLen, writePerm) + //@ ghost v := sl.View(b, 0, HopLen) + //@ assert v[2] == sl.GetByte(b, 0, HopLen, 2) && v[3] == sl.GetByte(b, 0, HopLen, 3) + //@ assert v[4] == sl.GetByte(b, 0, HopLen, 4) && v[5] == sl.GetByte(b, 0, HopLen, 5) + //@ assert v[6] == mac[0] && v[7] == mac[1] && v[8] == mac[2] + //@ assert v[9] == mac[3] && v[10] == mac[4] && v[11] == mac[5] + //@ assert v[2] == b2 && v[3] == b3 && v[4] == b4 && v[5] == b5 + //@ assert mac[0] == h.Mac[0] && mac[1] == h.Mac[1] && mac[2] == h.Mac[2] + //@ assert mac[3] == h.Mac[3] && mac[4] == h.Mac[4] && mac[5] == h.Mac[5] + //@ assert v[6:6+MacLen][0] == v[6] && v[6:6+MacLen][1] == v[7] && v[6:6+MacLen][2] == v[8] + //@ assert v[6:6+MacLen][3] == v[9] && v[6:6+MacLen][4] == v[10] && v[6:6+MacLen][5] == v[11] + //@ EqualSeqImplyEqualMac(v[6:6+MacLen], h.Mac) + //@ assert h.Abs() == BytesToIO_HF(v) //@ fold acc(h.Mem(), R11) return nil } diff --git a/pkg/slayers/path/hopfield_spec.gobra b/pkg/slayers/path/hopfield_spec.gobra index 816768b22..8a0702072 100644 --- a/pkg/slayers/path/hopfield_spec.gobra +++ b/pkg/slayers/path/hopfield_spec.gobra @@ -18,9 +18,7 @@ package path import ( "verification/io" - sl "verification/utils/slices" "verification/dependencies/encoding/binary" - . "verification/utils/definitions" ) pred (h *HopField) Mem() { @@ -40,72 +38,24 @@ pure func IO_ifsToIfs(ifs option[io.Ifs]) uint16 { return ifs == none[io.Ifs] ? 0 : uint16(get(ifs).V) } +// BytesToIO_HF takes the raw bytes of exactly one hop field (obtained +// by slicing the view of a buffer) and computes its abstract +// representation. It requires no permissions. ghost -requires 0 <= start && start <= middle -requires middle + HopLen <= end && end <= len(raw) -requires sl.Bytes(raw, start, end) +requires len(raw) == HopLen decreases -pure func BytesToIO_HF(raw [] byte, start int, middle int, end int) (io.HF) { - return let _ := sl.AssertSliceOverlap(raw, middle+2, middle+4) in - let _ := sl.AssertSliceOverlap(raw, middle+4, middle+6) in - let _ := sl.AssertSliceOverlap(raw, middle+6, middle+6+MacLen) in - unfolding sl.Bytes(raw, start, end) in - let inif2 := binary.BigEndian.Uint16(raw[middle+2:middle+4]) in - let egif2 := binary.BigEndian.Uint16(raw[middle+4:middle+6]) in - let op_inif2 := ifsToIO_ifs(inif2) in - let op_egif2 := ifsToIO_ifs(egif2) in +pure func BytesToIO_HF(raw seq[byte]) (io.HF) { + return let inif2 := binary.BigEndian.Uint16Spec(raw[2], raw[3]) in + let egif2 := binary.BigEndian.Uint16Spec(raw[4], raw[5]) in + let op_inif2 := ifsToIO_ifs(inif2) in + let op_egif2 := ifsToIO_ifs(egif2) in io.HF { InIF2: op_inif2, EgIF2: op_egif2, - HVF: AbsMac(FromSliceToMacArray(raw[middle+6:middle+6+MacLen])), + HVF: AbsMac(FromSeqToMacArray(raw[6:6+MacLen])), } } -// WidenBytesHopField shows the equality between the HF computed -// from raw bytes in slice 'raw' starting at position `offset` with -// the HF obtained from the slice 'raw[start:end]`. -ghost -requires 0 <= start && start <= offset -requires offset + HopLen <= end -requires end <= len(raw) -preserves acc(sl.Bytes(raw, 0, len(raw)), R55) -preserves acc(sl.Bytes(raw[start:end], 0, len(raw[start:end])), R55) -ensures BytesToIO_HF(raw, 0, offset, len(raw)) == - BytesToIO_HF(raw[start:end], 0, offset-start, end-start) -decreases -func WidenBytesHopField(raw []byte, offset int, start int, end int) { - unfold acc(sl.Bytes(raw, 0, len(raw)), R56) - unfold acc(sl.Bytes(raw[start:end], 0, len(raw[start:end])), R56) - hfBytes1 := BytesToIO_HF(raw, 0, offset, len(raw)) - hfBytes2 := BytesToIO_HF(raw[start:end], 0, offset-start, end-start) - - sl.AssertSliceOverlap(raw, start, end) - sl.AssertSliceOverlap(raw[start:end], offset-start+2, offset-start+4) - assert hfBytes1.InIF2 == hfBytes2.InIF2 - sl.AssertSliceOverlap(raw[start:end], offset-start+4, offset-start+6) - assert hfBytes1.EgIF2 == hfBytes2.EgIF2 - sl.AssertSliceOverlap(raw[start:end], offset-start+6, offset-start+6+MacLen) - - fold acc(sl.Bytes(raw, 0, len(raw)), R56) - fold acc(sl.Bytes(raw[start:end], 0, len(raw[start:end])), R56) -} - -// WidenBytesHopField shows the equality between the HF computed -// from raw bytes in slice 'raw' starting at position `offset` with -// the HF obtained from the slice 'raw[offset:offset+HopLen]`. -// It is a special case of `WidenBytesHopField`. -ghost -requires 0 <= offset -requires offset+HopLen <= len(raw) -preserves acc(sl.Bytes(raw, 0, len(raw)), R55) -preserves acc(sl.Bytes(raw[offset:offset+HopLen], 0, HopLen), R55) -ensures BytesToIO_HF(raw, 0, offset, len(raw)) == - BytesToIO_HF(raw[offset:offset+HopLen], 0, 0, HopLen) -decreases -func BytesToAbsHopFieldOffsetEq(raw [] byte, offset int) { - WidenBytesHopField(raw, offset, offset, offset+HopLen) -} - ghost decreases pure func (h HopField) Abs() (io.HF) { diff --git a/pkg/slayers/path/infofield.go b/pkg/slayers/path/infofield.go index 6f9e616aa..ad8445884 100644 --- a/pkg/slayers/path/infofield.go +++ b/pkg/slayers/path/infofield.go @@ -64,13 +64,15 @@ type InfoField struct { // @ preserves acc(inf) // @ preserves acc(slices.Bytes(raw, 0, len(raw)), R45) // @ ensures err == nil -// @ ensures BytesToAbsInfoField(raw, 0) == +// @ ensures BytesToAbsInfoField(slices.View(raw, 0, len(raw))[:InfoLen]) == // @ inf.ToAbsInfoField() // @ decreases func (inf *InfoField) DecodeFromBytes(raw []byte) (err error) { if len(raw) < InfoLen { return serrors.New("InfoField raw too short", "expected", InfoLen, "actual", len(raw)) } + //@ ghost v := slices.View(raw, 0, len(raw)) + //@ slices.ViewElems(raw, 0, len(raw), R50) //@ unfold acc(slices.Bytes(raw, 0, len(raw)), R50) inf.ConsDir = raw[0]&0x1 == 0x1 inf.Peer = raw[0]&0x2 == 0x2 @@ -79,8 +81,10 @@ func (inf *InfoField) DecodeFromBytes(raw []byte) (err error) { //@ assert &raw[4:8][0] == &raw[4] && &raw[4:8][1] == &raw[5] //@ assert &raw[4:8][2] == &raw[6] && &raw[4:8][3] == &raw[7] inf.Timestamp = binary.BigEndian.Uint32(raw[4:8]) + //@ assert v[0] == raw[0] && v[2] == raw[2] && v[3] == raw[3] + //@ assert v[4] == raw[4] && v[5] == raw[5] && v[6] == raw[6] && v[7] == raw[7] //@ fold acc(slices.Bytes(raw, 0, len(raw)), R50) - //@ assert reveal BytesToAbsInfoField(raw, 0) == + //@ assert reveal BytesToAbsInfoField(v[:InfoLen]) == //@ inf.ToAbsInfoField() return nil } @@ -92,7 +96,7 @@ func (inf *InfoField) DecodeFromBytes(raw []byte) (err error) { // @ preserves slices.Bytes(b, 0, len(b)) // @ ensures err == nil // @ ensures inf.ToAbsInfoField() == -// @ BytesToAbsInfoField(b, 0) +// @ BytesToAbsInfoField(slices.View(b, 0, len(b))[:InfoLen]) // @ decreases func (inf *InfoField) SerializeTo(b []byte) (err error) { if len(b) < InfoLen { @@ -105,32 +109,47 @@ func (inf *InfoField) SerializeTo(b []byte) (err error) { if inf.ConsDir { b[0] |= 0x1 } - //@ ghost tmpInfo1 := BytesToAbsInfoFieldHelper(b, 0) //@ bits.InfoFieldFirstByteSerializationLemmas() - //@ assert tmpInfo1.ConsDir == targetAbsInfo.ConsDir + //@ assert (b[0] & 0x1 == 0x1) == targetAbsInfo.ConsDir //@ ghost firstByte := b[0] if inf.Peer { b[0] |= 0x2 } - //@ tmpInfo2 := BytesToAbsInfoFieldHelper(b, 0) - //@ assert tmpInfo2.Peer == (b[0] & 0x2 == 0x2) - //@ assert tmpInfo2.ConsDir == (b[0] & 0x1 == 0x1) - //@ assert tmpInfo2.Peer == targetAbsInfo.Peer - //@ assert tmpInfo2.ConsDir == tmpInfo1.ConsDir - //@ assert tmpInfo2.ConsDir == targetAbsInfo.ConsDir + //@ assert (b[0] & 0x2 == 0x2) == targetAbsInfo.Peer + //@ assert (b[0] & 0x1 == 0x1) == (firstByte & 0x1 == 0x1) + //@ assert (b[0] & 0x1 == 0x1) == targetAbsInfo.ConsDir b[1] = 0 // reserved //@ assert &b[2:4][0] == &b[2] && &b[2:4][1] == &b[3] binary.BigEndian.PutUint16(b[2:4], inf.SegID) - //@ ghost tmpInfo3 := BytesToAbsInfoFieldHelper(b, 0) - //@ assert tmpInfo3.UInfo == targetAbsInfo.UInfo + //@ assert binary.BigEndian.Uint16Spec(b[2], b[3]) == inf.SegID //@ assert &b[4:8][0] == &b[4] && &b[4:8][1] == &b[5] //@ assert &b[4:8][2] == &b[6] && &b[4:8][3] == &b[7] binary.BigEndian.PutUint32(b[4:8], inf.Timestamp) - //@ ghost tmpInfo4 := BytesToAbsInfoFieldHelper(b, 0) - //@ assert tmpInfo4.AInfo == targetAbsInfo.AInfo + //@ assert binary.BigEndian.Uint32Spec(b[4], b[5], b[6], b[7]) == inf.Timestamp + //@ ghost b0 := b[0] + //@ ghost b2 := b[2] + //@ ghost b3 := b[3] + //@ ghost b4 := b[4] + //@ ghost b5 := b[5] + //@ ghost b6 := b[6] + //@ ghost b7 := b[7] //@ fold slices.Bytes(b, 0, len(b)) + // the GetByte terms instantiate the preservation postconditions of + // ViewElems, which carry the byte values across the lemma call + //@ assert slices.GetByte(b, 0, len(b), 0) == b0 + //@ assert slices.GetByte(b, 0, len(b), 2) == b2 && slices.GetByte(b, 0, len(b), 3) == b3 + //@ assert slices.GetByte(b, 0, len(b), 4) == b4 && slices.GetByte(b, 0, len(b), 5) == b5 + //@ assert slices.GetByte(b, 0, len(b), 6) == b6 && slices.GetByte(b, 0, len(b), 7) == b7 + //@ slices.ViewElems(b, 0, len(b), writePerm) + //@ ghost v := slices.View(b, 0, len(b)) + //@ assert v[0] == slices.GetByte(b, 0, len(b), 0) + //@ assert v[2] == slices.GetByte(b, 0, len(b), 2) && v[3] == slices.GetByte(b, 0, len(b), 3) + //@ assert v[4] == slices.GetByte(b, 0, len(b), 4) && v[5] == slices.GetByte(b, 0, len(b), 5) + //@ assert v[6] == slices.GetByte(b, 0, len(b), 6) && v[7] == slices.GetByte(b, 0, len(b), 7) + //@ assert v[0] == b0 && v[2] == b2 && v[3] == b3 + //@ assert v[4] == b4 && v[5] == b5 && v[6] == b6 && v[7] == b7 //@ assert inf.ToAbsInfoField() == - //@ reveal BytesToAbsInfoField(b, 0) + //@ reveal BytesToAbsInfoField(v[:InfoLen]) return nil } diff --git a/pkg/slayers/path/infofield_spec.gobra b/pkg/slayers/path/infofield_spec.gobra index f29c8099b..83f39a215 100644 --- a/pkg/slayers/path/infofield_spec.gobra +++ b/pkg/slayers/path/infofield_spec.gobra @@ -18,9 +18,7 @@ package path import ( "verification/io" - sl "verification/utils/slices" "verification/dependencies/encoding/binary" - . "verification/utils/definitions" ) ghost @@ -29,105 +27,50 @@ pure func InfoFieldOffset(currINF, headerOffset int) int { return headerOffset + InfoLen * currINF } -ghost -requires 0 <= currINF && 0 <= headerOffset -requires InfoFieldOffset(currINF, headerOffset) < len(raw) -requires sl.Bytes(raw, 0, len(raw)) -decreases -pure func ConsDir(raw []byte, currINF int, headerOffset int) bool { - return unfolding sl.Bytes(raw, 0, len(raw)) in - raw[InfoFieldOffset(currINF, headerOffset)] & 0x1 == 0x1 -} - -ghost -requires 0 <= currINF && 0 <= headerOffset -requires InfoFieldOffset(currINF, headerOffset) < len(raw) -requires sl.Bytes(raw, 0, len(raw)) -decreases -pure func Peer(raw []byte, currINF int, headerOffset int) bool { - return unfolding sl.Bytes(raw, 0, len(raw)) in - raw[InfoFieldOffset(currINF, headerOffset)] & 0x2 == 0x2 -} +// The parsing functions below take the raw bytes of exactly one info +// field (obtained by slicing the view of a buffer) and require no +// permissions. Callers select the relevant bytes with, e.g., +// sl.View(ub, 0, len(ub))[off:off+InfoLen]. ghost -requires 0 <= currINF && 0 <= headerOffset -requires InfoFieldOffset(currINF, headerOffset) + InfoLen < len(raw) -requires sl.Bytes(raw, 0, len(raw)) +requires len(raw) == InfoLen decreases -pure func Timestamp(raw []byte, currINF int, headerOffset int) io.Ainfo { - return let idx := InfoFieldOffset(currINF, headerOffset)+4 in - unfolding sl.Bytes(raw, 0, len(raw)) in - let _ := sl.AssertSliceOverlap(raw, idx, idx+4) in - io.Ainfo{uint(binary.BigEndian.Uint32(raw[idx:idx+4]))} +pure func ConsDir(raw seq[byte]) bool { + return raw[0] & 0x1 == 0x1 } ghost -requires 0 <= currINF && 0 <= headerOffset -requires InfoFieldOffset(currINF, headerOffset) + InfoLen < len(raw) -requires sl.Bytes(raw, 0, len(raw)) +requires len(raw) == InfoLen decreases -pure func AbsUinfo(raw []byte, currINF int, headerOffset int) set[io.MsgTerm] { - return let idx := InfoFieldOffset(currINF, headerOffset)+2 in - unfolding sl.Bytes(raw, 0, len(raw)) in - let _ := sl.AssertSliceOverlap(raw, idx, idx+2) in - AbsUInfoFromUint16(binary.BigEndian.Uint16(raw[idx:idx+2])) +pure func Peer(raw seq[byte]) bool { + return raw[0] & 0x2 == 0x2 } ghost -opaque -requires 0 <= middle -requires middle+InfoLen <= len(raw) -requires sl.Bytes(raw, 0, len(raw)) +requires len(raw) == InfoLen decreases -pure func BytesToAbsInfoField(raw [] byte, middle int) (io.AbsInfoField) { - return unfolding sl.Bytes(raw, 0, len(raw)) in - BytesToAbsInfoFieldHelper(raw, middle) +pure func Timestamp(raw seq[byte]) io.Ainfo { + return io.Ainfo{uint(binary.BigEndian.Uint32Spec(raw[4], raw[5], raw[6], raw[7]))} } ghost -requires 0 <= middle -requires middle+InfoLen <= len(raw) -requires forall i int :: { &raw[i] } middle <= i && i < len(raw) ==> - acc(&raw[i]) +requires len(raw) == InfoLen decreases -pure func BytesToAbsInfoFieldHelper(raw [] byte, middle int) (io.AbsInfoField) { - return let _ := sl.AssertSliceOverlap(raw, middle+2, middle+4) in - let _ := sl.AssertSliceOverlap(raw, middle+4, middle+8) in - io.AbsInfoField { - AInfo: io.Ainfo{uint(binary.BigEndian.Uint32(raw[middle+4:middle+8]))}, - UInfo: AbsUInfoFromUint16(binary.BigEndian.Uint16(raw[middle+2:middle+4])), - ConsDir: raw[middle] & 0x1 == 0x1, - Peer: raw[middle] & 0x2 == 0x2, - } +pure func AbsUinfo(raw seq[byte]) set[io.MsgTerm] { + return AbsUInfoFromUint16(binary.BigEndian.Uint16Spec(raw[2], raw[3])) } ghost -requires 0 <= middle -requires middle+InfoLen <= len(raw) -preserves acc(sl.Bytes(raw, 0, len(raw)), R55) -preserves acc(sl.Bytes(raw[middle:middle+InfoLen], 0, InfoLen), R55) -ensures BytesToAbsInfoField(raw, middle) == - BytesToAbsInfoField(raw[middle:middle+InfoLen], 0) +opaque +requires len(raw) == InfoLen decreases -func BytesToAbsInfoFieldOffsetEq(raw [] byte, middle int) { - start := middle - end := middle+InfoLen - unfold acc(sl.Bytes(raw, 0, len(raw)), R56) - unfold acc(sl.Bytes(raw[start:end], 0, InfoLen), R56) - absInfo1 := reveal BytesToAbsInfoField(raw, start) - absInfo2 := reveal BytesToAbsInfoField(raw[start:end], 0) - - assert absInfo1.ConsDir == absInfo2.ConsDir - assert absInfo1.Peer == absInfo2.Peer - sl.AssertSliceOverlap(raw, start, end) - sl.AssertSliceOverlap(raw[start:end], 4, 8) - assert absInfo1.AInfo == absInfo2.AInfo - sl.AssertSliceOverlap(raw[start:end], 2, 4) - assert absInfo1.UInfo == absInfo2.UInfo - assert absInfo1 == absInfo2 - - fold acc(sl.Bytes(raw, 0, len(raw)), R56) - fold acc(sl.Bytes(raw[start:end], 0, InfoLen), R56) +pure func BytesToAbsInfoField(raw seq[byte]) (io.AbsInfoField) { + return io.AbsInfoField { + AInfo: Timestamp(raw), + UInfo: AbsUinfo(raw), + ConsDir: ConsDir(raw), + Peer: Peer(raw), + } } ghost @@ -139,4 +82,4 @@ pure func (inf InfoField) ToAbsInfoField() (io.AbsInfoField) { ConsDir: inf.ConsDir, Peer: inf.Peer, } -} \ No newline at end of file +} diff --git a/pkg/slayers/path/io_msgterm_spec.gobra b/pkg/slayers/path/io_msgterm_spec.gobra index 7331673bc..91acc1705 100644 --- a/pkg/slayers/path/io_msgterm_spec.gobra +++ b/pkg/slayers/path/io_msgterm_spec.gobra @@ -18,7 +18,6 @@ package path import ( "verification/io" - . "verification/utils/definitions" ) // At the moment, we assume that all cryptographic operations performed at the code level @@ -34,28 +33,29 @@ ghost decreases pure func AbsMac(mac [MacLen]byte) (io.MsgTerm) -// The following function converts a slice with at least `MacLen` elements into -// an (exclusive) array containing the mac. Note that there are no permissions -// involved for accessing exclusive arrays. +// The following function converts a sequence with exactly `MacLen` elements +// into an (exclusive) array containing the mac. Note that there are no +// permissions involved for accessing exclusive arrays or sequences. ghost -requires MacLen <= len(mac) -requires forall i int :: { &mac[i] } 0 <= i && i < MacLen ==> acc(&mac[i]) +requires len(mac) == MacLen ensures len(res) == MacLen ensures forall i int :: { res[i] } 0 <= i && i < MacLen ==> mac[i] == res[i] decreases -pure func FromSliceToMacArray(mac []byte) (res [MacLen]byte) { +pure func FromSeqToMacArray(mac seq[byte]) (res [MacLen]byte) { return [MacLen]byte{ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] } } ghost requires len(mac1) == MacLen -requires forall i int :: { &mac1[i] } 0 <= i && i < MacLen ==> acc(&mac1[i], R50) -requires forall i int :: { &mac1[i] } 0 <= i && i < MacLen ==> mac1[i] == mac2[i] -ensures forall i int :: { &mac1[i] } 0 <= i && i < MacLen ==> acc(&mac1[i], R50) -ensures AbsMac(FromSliceToMacArray(mac1)) == AbsMac(mac2) +// the elementwise premises are stated for each index instead of with a +// quantifier: all callers have the ground facts at hand, and the ground +// form keeps the instantiation surface of the serializer proofs small +requires mac1[0] == mac2[0] && mac1[1] == mac2[1] && mac1[2] == mac2[2] +requires mac1[3] == mac2[3] && mac1[4] == mac2[4] && mac1[5] == mac2[5] +ensures AbsMac(FromSeqToMacArray(mac1)) == AbsMac(mac2) decreases -func EqualBytesImplyEqualMac(mac1 []byte, mac2 [MacLen]byte) { - mac1Arr := FromSliceToMacArray(mac1) +func EqualSeqImplyEqualMac(mac1 seq[byte], mac2 [MacLen]byte) { + mac1Arr := FromSeqToMacArray(mac1) assert mac1Arr == mac2 assert mac1Arr[0] == mac2[0] && mac1Arr[1] == mac2[1] && diff --git a/pkg/slayers/path/scion/base.go b/pkg/slayers/path/scion/base.go index 1e0b48d53..9b3ce951f 100644 --- a/pkg/slayers/path/scion/base.go +++ b/pkg/slayers/path/scion/base.go @@ -83,10 +83,10 @@ type Base struct { // @ ensures r == nil ==> // @ s.Mem() && // @ s.GetBase().WeaklyValid() && -// @ s.DecodeFromBytesSpec(data) +// @ s.DecodeFromBytesSpec(sl.View(data, 0, len(data))) // @ ensures len(data) < MetaLen ==> r != nil // posts for IO: -// @ ensures r == nil ==> s.GetBase().EqAbsHeader(data) +// @ ensures r == nil ==> s.GetBase().EqAbsHeader(sl.View(data, 0, len(data))) // @ decreases func (s *Base) DecodeFromBytes(data []byte) (r error) { // PathMeta takes care of bounds check. @@ -149,8 +149,8 @@ func (s *Base) DecodeFromBytes(data []byte) (r error) { //@ defer fold s.NonInitMem() return serrors.New("NumHops too large", "NumHops", s.NumHops, "Maximum", MaxHops) } - //@ assert s.PathMeta.EqAbsHeader(data) - //@ assert s.EqAbsHeader(data) + //@ assert s.PathMeta.EqAbsHeader(sl.View(data, 0, len(data))) + //@ assert s.EqAbsHeader(sl.View(data, 0, len(data))) //@ fold s.Mem() return nil } @@ -253,7 +253,7 @@ type MetaHdr struct { // @ preserves acc(sl.Bytes(raw, 0, len(raw)), R50) // @ ensures (len(raw) >= MetaLen) == (e == nil) // @ ensures e == nil ==> m.InBounds() -// @ ensures e == nil ==> m.DecodeFromBytesSpec(raw) +// @ ensures e == nil ==> m.DecodeFromBytesSpec(sl.View(raw, 0, len(raw))) // @ ensures e != nil ==> e.ErrorMem() // @ decreases func (m *MetaHdr) DecodeFromBytes(raw []byte) (e error) { @@ -261,7 +261,12 @@ func (m *MetaHdr) DecodeFromBytes(raw []byte) (e error) { // (VerifiedSCION) added cast, otherwise Gobra cannot verify call return serrors.New("MetaHdr raw too short", "expected", int(MetaLen), "actual", int(len(raw))) } - //@ unfold acc(sl.Bytes(raw, 0, len(raw)), R50) + //@ ghost v := sl.View(raw, 0, len(raw)) + //@ sl.ViewElems(raw, 0, len(raw), R51) + // unfolding only part of the held fraction pins the view of raw: + // the retained instance is untouched, so the view after refolding + // is the same as the captured one + //@ unfold acc(sl.Bytes(raw, 0, len(raw)), R51) line := binary.BigEndian.Uint32(raw) m.CurrINF = uint8(line >> 30) m.CurrHF = uint8(line>>24) & 0x3F @@ -273,7 +278,10 @@ func (m *MetaHdr) DecodeFromBytes(raw []byte) (e error) { //@ bit.And3fAtMost64(uint8(line>>12)) //@ bit.And3fAtMost64(uint8(line>>6)) //@ bit.And3fAtMost64(uint8(line)) - //@ fold acc(sl.Bytes(raw, 0, len(raw)), R50) + //@ assert v[0] == raw[0] && v[1] == raw[1] && v[2] == raw[2] && v[3] == raw[3] + //@ fold acc(sl.Bytes(raw, 0, len(raw)), R51) + //@ assert sl.View(raw, 0, len(raw)) == v + //@ assert line == binary.BigEndian.Uint32Spec(v[0], v[1], v[2], v[3]) return nil } @@ -283,7 +291,7 @@ func (m *MetaHdr) DecodeFromBytes(raw []byte) (e error) { // @ preserves acc(m, R50) // @ preserves sl.Bytes(b, 0, len(b)) // @ ensures e == nil -// @ ensures m.SerializeToSpec(b) +// @ ensures m.SerializeToSpec(sl.View(b, 0, len(b))) // @ decreases func (m *MetaHdr) SerializeTo(b []byte) (e error) { if len(b) < MetaLen { @@ -296,7 +304,15 @@ func (m *MetaHdr) SerializeTo(b []byte) (e error) { line |= uint32(m.SegLen[2] & 0x3F) //@ unfold acc(sl.Bytes(b, 0, len(b))) binary.BigEndian.PutUint32(b, line) + //@ ghost b0 := b[0] + //@ ghost b1 := b[1] + //@ ghost b2 := b[2] + //@ ghost b3 := b[3] //@ fold acc(sl.Bytes(b, 0, len(b))) + //@ sl.ViewElems(b, 0, len(b), writePerm) + //@ ghost v := sl.View(b, 0, len(b)) + //@ assert v[0] == b0 && v[1] == b1 && v[2] == b2 && v[3] == b3 + //@ assert binary.BigEndian.PutUint32Spec(v[0], v[1], v[2], v[3], line) return nil } diff --git a/pkg/slayers/path/scion/base_spec.gobra b/pkg/slayers/path/scion/base_spec.gobra index f99b1fc47..59e0a5c31 100644 --- a/pkg/slayers/path/scion/base_spec.gobra +++ b/pkg/slayers/path/scion/base_spec.gobra @@ -18,10 +18,6 @@ package scion import ( "encoding/binary" - "github.com/scionproto/scion/pkg/slayers/path" - sl "github.com/scionproto/scion/verification/utils/slices" - - . "github.com/scionproto/scion/verification/utils/definitions" ) pred (b *Base) NonInitMem() { @@ -244,29 +240,22 @@ pure func DecodedFrom(line uint32) MetaHdr { } ghost -requires sl.Bytes(b, 0, len(b)) decreases -pure func (m MetaHdr) DecodeFromBytesSpec(b []byte) bool { - return MetaLen <= len(b) && +pure func (m MetaHdr) DecodeFromBytesSpec(raw seq[byte]) bool { + return MetaLen <= len(raw) && 0 <= m.CurrINF && m.CurrINF <= 3 && 0 <= m.CurrHF && m.CurrHF < 64 && m.SegsInBounds() && - let lenR := len(b) in - let b0 := sl.GetByte(b, 0, lenR, 0) in - let b1 := sl.GetByte(b, 0, lenR, 1) in - let b2 := sl.GetByte(b, 0, lenR, 2) in - let b3 := sl.GetByte(b, 0, lenR, 3) in - let line := binary.BigEndian.Uint32Spec(b0, b1, b2, b3) in + let line := binary.BigEndian.Uint32Spec(raw[0], raw[1], raw[2], raw[3]) in DecodedFrom(line) == m } ghost requires s.Mem() -requires sl.Bytes(b, 0, len(b)) decreases -pure func (s *Base) DecodeFromBytesSpec(b []byte) bool { +pure func (s *Base) DecodeFromBytesSpec(raw seq[byte]) bool { return unfolding s.Mem() in - s.PathMeta.DecodeFromBytesSpec(b) + s.PathMeta.DecodeFromBytesSpec(raw) } ghost @@ -296,38 +285,29 @@ pure func (m MetaHdr) SerializedToLine() uint32 { } ghost -requires sl.Bytes(b, 0, len(b)) decreases -pure func (m MetaHdr) SerializeToSpec(b []byte) bool { - return MetaLen <= len(b) && - let lenR := len(b) in - let b0 := sl.GetByte(b, 0, lenR, 0) in - let b1 := sl.GetByte(b, 0, lenR, 1) in - let b2 := sl.GetByte(b, 0, lenR, 2) in - let b3 := sl.GetByte(b, 0, lenR, 3) in - let v := m.SerializedToLine() in - binary.BigEndian.PutUint32Spec(b0, b1, b2, b3, v) +pure func (m MetaHdr) SerializeToSpec(raw seq[byte]) bool { + return MetaLen <= len(raw) && + let v := m.SerializedToLine() in + binary.BigEndian.PutUint32Spec(raw[0], raw[1], raw[2], raw[3], v) } ghost -requires sl.Bytes(ub, 0, len(ub)) decreases -pure func (s Base) EqAbsHeader(ub []byte) bool { - // we compute the sublice ub[:MetaLen] inside this function instead - // of expecting the correct subslice to be passed, otherwise this function - // becomes too cumbersome to use in calls from (*Raw).EqAbsHeader due to the - // lack of a folding expression. Same goes for MetaHdr.EqAbsHeader. - return MetaLen <= len(ub) && - s == RawBytesToBase(ub) +pure func (s Base) EqAbsHeader(raw seq[byte]) bool { + // we take the whole view of the packet instead of expecting the + // subsequence raw[:MetaLen] to be passed, otherwise this function + // becomes too cumbersome to use in calls from (*Raw).EqAbsHeader. + // Same goes for MetaHdr.EqAbsHeader. + return MetaLen <= len(raw) && + s == RawBytesToBase(raw) } ghost -requires sl.Bytes(ub, 0, len(ub)) decreases -pure func (s MetaHdr) EqAbsHeader(ub []byte) bool { - return MetaLen <= len(ub) && - unfolding sl.Bytes(ub, 0, len(ub)) in - s == DecodedFrom(binary.BigEndian.Uint32(ub[:MetaLen])) +pure func (s MetaHdr) EqAbsHeader(raw seq[byte]) bool { + return MetaLen <= len(raw) && + s == DecodedFrom(binary.BigEndian.Uint32Spec(raw[0], raw[1], raw[2], raw[3])) } /** Lemma proven in /VerifiedSCION/verification/utils/bitwise/proofs.dfy **/ diff --git a/pkg/slayers/path/scion/decoded.go b/pkg/slayers/path/scion/decoded.go index 27eb6e8d3..281d4f428 100644 --- a/pkg/slayers/path/scion/decoded.go +++ b/pkg/slayers/path/scion/decoded.go @@ -119,6 +119,17 @@ func (s *Decoded) DecodeFromBytes(data []byte) (r error) { offset += path.HopLen } //@ sl.CombineAtIndex_Bytes(data, 0, len(data), offset, R43) + // the retained fraction of Bytes(data) pins its view, so the view + // here is the one Base.DecodeFromBytes's postcondition speaks + // about; ViewElems bridges its elements to the GetByte terms of + // the postcondition + //@ sl.ViewElems(data, 0, len(data), R43) + //@ ghost vD := sl.View(data, 0, len(data)) + //@ assert vD[0] == sl.GetByte(data, 0, len(data), 0) + //@ assert vD[1] == sl.GetByte(data, 0, len(data), 1) + //@ assert vD[2] == sl.GetByte(data, 0, len(data), 2) + //@ assert vD[3] == sl.GetByte(data, 0, len(data), 3) + //@ assert s.Base.DecodeFromBytesSpec(vD) //@ fold s.Mem(data) return nil } diff --git a/pkg/slayers/path/scion/info_hop_setter_lemmas.gobra b/pkg/slayers/path/scion/info_hop_setter_lemmas.gobra index 886d6c3d2..6362fdb27 100644 --- a/pkg/slayers/path/scion/info_hop_setter_lemmas.gobra +++ b/pkg/slayers/path/scion/info_hop_setter_lemmas.gobra @@ -18,18 +18,17 @@ package scion import ( "github.com/scionproto/scion/pkg/slayers/path" - . "verification/utils/definitions" sl "verification/utils/slices" "verification/io" ) /*** This file contains helpful lemmas for proving SetInfoField and SetHopfield. ***/ // Our abstract translation functions (CurrSeg, LeftSeg, RightSeg, MidSeg) are defined based on the -// entire byte slice of the concrete packet. This approach makes proving updates to the bytes very difficult. -// In this file, we introduce new translation functions that rely only on the hopfields byte slice and -// the infofield of a segment. We prove that these new functions are equivalent to the original ones -// and can be translated to each other. With these new functions, the proofs for SetInfoField and SetHopfield -// are greatly simplified. +// view of the entire packet. This approach makes proving updates to the bytes very difficult. +// In this file, we introduce new translation functions that rely only on the view of the hopfields +// of a segment and the infofield of that segment. We prove that these new functions are equivalent +// to the original ones and can be translated to each other. With these new functions, the proofs +// for SetInfoField and SetHopfield are greatly simplified. // InfofieldByteSlice returns the byte slice of the infofield corresponding to the @@ -48,6 +47,21 @@ pure func InfofieldByteSlice(raw []byte, currInfIdx int) ([]byte) { raw[infOffset:infOffset + path.InfoLen] } +// InfofieldByteSeq is the view-level analogue of InfofieldByteSlice: it returns +// the bytes of the infofield corresponding to the specified currInfIdx argument +// in the view of the packet. +ghost +requires 0 <= currInfIdx +requires path.InfoFieldOffset(currInfIdx, MetaLen) + path.InfoLen <= len(raw) +ensures len(res) == path.InfoLen +decreases +pure func InfofieldByteSeq(raw seq[byte], currInfIdx int) (res seq[byte]) { + return let infOffset := currInfIdx == 4 ? + path.InfoFieldOffset(0, MetaLen) : + path.InfoFieldOffset(currInfIdx, MetaLen) in + raw[infOffset:infOffset + path.InfoLen] +} + // HopfieldsStartIdx returns index of the first byte of the hopfields of a segment // specified by the currInfIdx argument. Although a packet can have only three segments, // we use currInfIdx == 4 to represent the first segment in our translation from @@ -65,7 +79,7 @@ pure func HopfieldsStartIdx(currInfIdx int, segs io.SegLens) int { infOffset + (segs.Seg1Len + segs.Seg2Len) * path.HopLen } -// HopfieldsStartIdx returns index of the last byte of the hopfields of a segment +// HopfieldsEndIdx returns index of the last byte of the hopfields of a segment // specified by the currInfIdx argument. Although a packet can have only three segments, // we use currInfIdx == 4 to represent the first segment in our translation from // concrete packets to abstract packets. This requires the special case that @@ -82,7 +96,7 @@ pure func HopfieldsEndIdx(currInfIdx int, segs io.SegLens) int { infOffset + (segs.Seg1Len + segs.Seg2Len + segs.Seg3Len) * path.HopLen } -// HopfieldsStartIdx returns returns the byte slice of the hopfields of a segment +// HopfieldsByteSlice returns the byte slice of the hopfields of a segment // specified by the currInfIdx argument. Although a packet can have only three segments, // we use currInfIdx == 4 to represent the first segment in our translation from // concrete packets to abstract packets. This requires the special case that @@ -93,9 +107,22 @@ requires 0 <= currInfIdx requires PktLen(segs, MetaLen) <= len(raw) decreases pure func HopfieldsByteSlice(raw []byte, currInfIdx int, segs io.SegLens) ([]byte) { - return let numInf := segs.NumInfoFields() in - let infOffset := path.InfoFieldOffset(numInf, MetaLen) in - let start := HopfieldsStartIdx(currInfIdx, segs) in + return let start := HopfieldsStartIdx(currInfIdx, segs) in + let end := HopfieldsEndIdx(currInfIdx, segs) in + raw[start:end] +} + +// HopfieldsByteSeq is the view-level analogue of HopfieldsByteSlice: it returns +// the bytes of the hopfields of the segment specified by the currInfIdx argument +// in the view of the packet. +ghost +requires segs.Valid() +requires 0 <= currInfIdx +requires PktLen(segs, MetaLen) <= len(raw) +ensures len(res) == HopfieldsEndIdx(currInfIdx, segs) - HopfieldsStartIdx(currInfIdx, segs) +decreases +pure func HopfieldsByteSeq(raw seq[byte], currInfIdx int, segs io.SegLens) (res seq[byte]) { + return let start := HopfieldsStartIdx(currInfIdx, segs) in let end := HopfieldsEndIdx(currInfIdx, segs) in raw[start:end] } @@ -111,17 +138,39 @@ ensures acc(sl.Bytes(HopfieldsByteSlice(raw, 0, segs), 0, segs.Seg1Len * path.H ensures acc(sl.Bytes(HopfieldsByteSlice(raw, 1, segs), 0, segs.Seg2Len * path.HopLen), p) ensures acc(sl.Bytes(HopfieldsByteSlice(raw, 2, segs), 0, segs.Seg3Len * path.HopLen), p) ensures acc(sl.Bytes(raw[HopfieldsEndIdx(2, segs):], 0, len(raw[HopfieldsEndIdx(2, segs):])), p) +ensures sl.View(raw[:HopfieldsStartIdx(0, segs)], 0, HopfieldsStartIdx(0, segs)) == + old(sl.View(raw, 0, len(raw)))[:HopfieldsStartIdx(0, segs)] +ensures sl.View(HopfieldsByteSlice(raw, 0, segs), 0, segs.Seg1Len * path.HopLen) == + old(sl.View(raw, 0, len(raw)))[HopfieldsStartIdx(0, segs):HopfieldsEndIdx(0, segs)] +ensures sl.View(HopfieldsByteSlice(raw, 1, segs), 0, segs.Seg2Len * path.HopLen) == + old(sl.View(raw, 0, len(raw)))[HopfieldsStartIdx(1, segs):HopfieldsEndIdx(1, segs)] +ensures sl.View(HopfieldsByteSlice(raw, 2, segs), 0, segs.Seg3Len * path.HopLen) == + old(sl.View(raw, 0, len(raw)))[HopfieldsStartIdx(2, segs):HopfieldsEndIdx(2, segs)] +ensures sl.View(raw[HopfieldsEndIdx(2, segs):], 0, len(raw) - HopfieldsEndIdx(2, segs)) == + old(sl.View(raw, 0, len(raw)))[HopfieldsEndIdx(2, segs):] decreases func SliceBytesIntoSegments(raw []byte, segs io.SegLens, p perm) { - sl.SplitByIndex_Bytes(raw, 0, len(raw), HopfieldsStartIdx(0, segs), p) - sl.SplitByIndex_Bytes(raw, HopfieldsStartIdx(0, segs), len(raw), HopfieldsEndIdx(0, segs), p) - sl.SplitByIndex_Bytes(raw, HopfieldsStartIdx(1, segs), len(raw), HopfieldsEndIdx(1, segs), p) - sl.SplitByIndex_Bytes(raw, HopfieldsStartIdx(2, segs), len(raw), HopfieldsEndIdx(2, segs), p) - sl.Reslice_Bytes(raw, 0, HopfieldsStartIdx(0, segs), p) - sl.Reslice_Bytes(raw, HopfieldsStartIdx(0, segs), HopfieldsEndIdx(0, segs), p) - sl.Reslice_Bytes(raw, HopfieldsStartIdx(1, segs), HopfieldsEndIdx(1, segs), p) - sl.Reslice_Bytes(raw, HopfieldsStartIdx(2, segs), HopfieldsEndIdx(2, segs), p) - sl.Reslice_Bytes(raw, HopfieldsEndIdx(2, segs), len(raw), p) + v := sl.View(raw, 0, len(raw)) + hs0 := HopfieldsStartIdx(0, segs) + he0 := HopfieldsEndIdx(0, segs) + he1 := HopfieldsEndIdx(1, segs) + he2 := HopfieldsEndIdx(2, segs) + sl.SplitByIndex_Bytes(raw, 0, len(raw), hs0, p) + assert sl.View(raw, hs0, len(raw)) == v[hs0:] + sl.SplitByIndex_Bytes(raw, hs0, len(raw), he0, p) + assert v[hs0:][:he0 - hs0] == v[hs0:he0] + assert v[hs0:][he0 - hs0:] == v[he0:] + sl.SplitByIndex_Bytes(raw, he0, len(raw), he1, p) + assert v[he0:][:he1 - he0] == v[he0:he1] + assert v[he0:][he1 - he0:] == v[he1:] + sl.SplitByIndex_Bytes(raw, he1, len(raw), he2, p) + assert v[he1:][:he2 - he1] == v[he1:he2] + assert v[he1:][he2 - he1:] == v[he2:] + sl.Reslice_Bytes(raw, 0, hs0, p) + sl.Reslice_Bytes(raw, hs0, he0, p) + sl.Reslice_Bytes(raw, he0, he1, p) + sl.Reslice_Bytes(raw, he1, he2, p) + sl.Reslice_Bytes(raw, he2, len(raw), p) } // CombineBytesFromSegments combines the three hopfield segments of a packet into a single slice of bytes. @@ -135,17 +184,37 @@ requires acc(sl.Bytes(HopfieldsByteSlice(raw, 1, segs), 0, segs.Seg2Len*path.Hop requires acc(sl.Bytes(HopfieldsByteSlice(raw, 2, segs), 0, segs.Seg3Len*path.HopLen), p) requires acc(sl.Bytes(raw[HopfieldsEndIdx(2, segs):], 0, len(raw[HopfieldsEndIdx(2, segs):])), p) ensures acc(sl.Bytes(raw, 0, len(raw)), p) +ensures sl.View(raw, 0, len(raw))[:HopfieldsStartIdx(0, segs)] == + old(sl.View(raw[:HopfieldsStartIdx(0, segs)], 0, HopfieldsStartIdx(0, segs))) +ensures sl.View(raw, 0, len(raw))[HopfieldsStartIdx(0, segs):HopfieldsEndIdx(0, segs)] == + old(sl.View(HopfieldsByteSlice(raw, 0, segs), 0, segs.Seg1Len*path.HopLen)) +ensures sl.View(raw, 0, len(raw))[HopfieldsStartIdx(1, segs):HopfieldsEndIdx(1, segs)] == + old(sl.View(HopfieldsByteSlice(raw, 1, segs), 0, segs.Seg2Len*path.HopLen)) +ensures sl.View(raw, 0, len(raw))[HopfieldsStartIdx(2, segs):HopfieldsEndIdx(2, segs)] == + old(sl.View(HopfieldsByteSlice(raw, 2, segs), 0, segs.Seg3Len*path.HopLen)) +ensures sl.View(raw, 0, len(raw))[HopfieldsEndIdx(2, segs):] == + old(sl.View(raw[HopfieldsEndIdx(2, segs):], 0, len(raw) - HopfieldsEndIdx(2, segs))) decreases func CombineBytesFromSegments(raw []byte, segs io.SegLens, p perm) { - sl.Unslice_Bytes(raw, HopfieldsEndIdx(2, segs), len(raw), p) - sl.Unslice_Bytes(raw, HopfieldsStartIdx(2, segs), HopfieldsEndIdx(2, segs), p) - sl.Unslice_Bytes(raw, HopfieldsStartIdx(1, segs), HopfieldsEndIdx(1, segs), p) - sl.Unslice_Bytes(raw, HopfieldsStartIdx(0, segs), HopfieldsEndIdx(0, segs), p) - sl.Unslice_Bytes(raw, 0, HopfieldsStartIdx(0, segs), p) - sl.CombineAtIndex_Bytes(raw, HopfieldsStartIdx(2, segs), len(raw), HopfieldsEndIdx(2, segs), p) - sl.CombineAtIndex_Bytes(raw, HopfieldsStartIdx(1, segs), len(raw), HopfieldsEndIdx(1, segs), p) - sl.CombineAtIndex_Bytes(raw, HopfieldsStartIdx(0, segs), len(raw), HopfieldsEndIdx(0, segs), p) - sl.CombineAtIndex_Bytes(raw, 0, len(raw), HopfieldsStartIdx(0, segs), p) + hs0 := HopfieldsStartIdx(0, segs) + he0 := HopfieldsEndIdx(0, segs) + he1 := HopfieldsEndIdx(1, segs) + he2 := HopfieldsEndIdx(2, segs) + sl.Unslice_Bytes(raw, he2, len(raw), p) + sl.Unslice_Bytes(raw, he1, he2, p) + sl.Unslice_Bytes(raw, he0, he1, p) + sl.Unslice_Bytes(raw, hs0, he0, p) + sl.Unslice_Bytes(raw, 0, hs0, p) + sl.CombineAtIndex_Bytes(raw, he1, len(raw), he2, p) + sl.CombineAtIndex_Bytes(raw, he0, len(raw), he1, p) + sl.CombineAtIndex_Bytes(raw, hs0, len(raw), he0, p) + sl.CombineAtIndex_Bytes(raw, 0, len(raw), hs0, p) + v := sl.View(raw, 0, len(raw)) + assert v[:hs0] == old(sl.View(raw[:hs0], 0, hs0)) + assert v[hs0:he0] == old(sl.View(raw[hs0:he0], 0, he0 - hs0)) + assert v[he0:he1] == old(sl.View(raw[he0:he1], 0, he1 - he0)) + assert v[he1:he2] == old(sl.View(raw[he1:he2], 0, he2 - he1)) + assert v[he2:] == old(sl.View(raw[he2:], 0, len(raw) - he2)) } // SliceBytesIntoInfoFields splits the raw bytes of a packet into its infofields @@ -160,8 +229,18 @@ ensures acc(sl.Bytes(InfofieldByteSlice(raw, 0), 0, path.InfoLen), p) ensures 1 < numInf ==> acc(sl.Bytes(InfofieldByteSlice(raw, 1), 0, path.InfoLen), p) ensures 2 < numInf ==> acc(sl.Bytes(InfofieldByteSlice(raw, 2), 0, path.InfoLen), p) ensures acc(sl.Bytes(raw[HopfieldsStartIdx(0, segs):], 0, len(raw[HopfieldsStartIdx(0, segs):])), p) +ensures sl.View(raw[:MetaLen], 0, MetaLen) == old(sl.View(raw, 0, len(raw)))[:MetaLen] +ensures sl.View(InfofieldByteSlice(raw, 0), 0, path.InfoLen) == + old(sl.View(raw, 0, len(raw)))[path.InfoFieldOffset(0, MetaLen):path.InfoFieldOffset(0, MetaLen) + path.InfoLen] +ensures 1 < numInf ==> sl.View(InfofieldByteSlice(raw, 1), 0, path.InfoLen) == + old(sl.View(raw, 0, len(raw)))[path.InfoFieldOffset(1, MetaLen):path.InfoFieldOffset(1, MetaLen) + path.InfoLen] +ensures 2 < numInf ==> sl.View(InfofieldByteSlice(raw, 2), 0, path.InfoLen) == + old(sl.View(raw, 0, len(raw)))[path.InfoFieldOffset(2, MetaLen):path.InfoFieldOffset(2, MetaLen) + path.InfoLen] +ensures sl.View(raw[HopfieldsStartIdx(0, segs):], 0, len(raw) - HopfieldsStartIdx(0, segs)) == + old(sl.View(raw, 0, len(raw)))[HopfieldsStartIdx(0, segs):] decreases func SliceBytesIntoInfoFields(raw []byte, numInf int, segs io.SegLens, p perm) { + v := sl.View(raw, 0, len(raw)) sl.SplitByIndex_Bytes(raw, 0, len(raw), MetaLen, p) sl.SplitByIndex_Bytes(raw, MetaLen, len(raw), path.InfoFieldOffset(1, MetaLen), p) sl.Reslice_Bytes(raw, 0, MetaLen, p) @@ -192,6 +271,15 @@ requires 1 < numInf ==> acc(sl.Bytes(InfofieldByteSlice(raw, 1), 0, path.InfoLen requires 2 < numInf ==> acc(sl.Bytes(InfofieldByteSlice(raw, 2), 0, path.InfoLen), p) requires acc(sl.Bytes(raw[HopfieldsStartIdx(0, segs):], 0, len(raw[HopfieldsStartIdx(0, segs):])), p) ensures acc(sl.Bytes(raw, 0, len(raw)), p) +ensures sl.View(raw, 0, len(raw))[:MetaLen] == old(sl.View(raw[:MetaLen], 0, MetaLen)) +ensures sl.View(raw, 0, len(raw))[path.InfoFieldOffset(0, MetaLen):path.InfoFieldOffset(0, MetaLen) + path.InfoLen] == + old(sl.View(InfofieldByteSlice(raw, 0), 0, path.InfoLen)) +ensures 1 < numInf ==> sl.View(raw, 0, len(raw))[path.InfoFieldOffset(1, MetaLen):path.InfoFieldOffset(1, MetaLen) + path.InfoLen] == + old(sl.View(InfofieldByteSlice(raw, 1), 0, path.InfoLen)) +ensures 2 < numInf ==> sl.View(raw, 0, len(raw))[path.InfoFieldOffset(2, MetaLen):path.InfoFieldOffset(2, MetaLen) + path.InfoLen] == + old(sl.View(InfofieldByteSlice(raw, 2), 0, path.InfoLen)) +ensures sl.View(raw, 0, len(raw))[HopfieldsStartIdx(0, segs):] == + old(sl.View(raw[HopfieldsStartIdx(0, segs):], 0, len(raw) - HopfieldsStartIdx(0, segs))) decreases func CombineBytesFromInfoFields(raw []byte, numInf int, segs io.SegLens, p perm) { sl.Unslice_Bytes(raw, HopfieldsStartIdx(0, segs), len(raw), p) @@ -213,25 +301,25 @@ func CombineBytesFromInfoFields(raw []byte, numInf int, segs io.SegLens, p perm) } // CurrSegWithInfo returns the abstract representation of the current segment of a packet. -// Unlike CurrSeg, it relies solely on the hopfield byte slice and an infofield instead of -// the entire raw bytes of the packet. This approach simplifies the verification of changes -// within a segment after updates to the packet's raw bytes. +// Unlike CurrSeg, it relies solely on the view of the hopfields of the segment and an +// infofield instead of the view of the entire packet. This approach simplifies the +// verification of changes within a segment after updates to the packet's raw bytes. ghost opaque requires 0 < SegLen requires 0 <= currHfIdx && currHfIdx <= SegLen requires SegLen * path.HopLen == len(hopfields) -requires sl.Bytes(hopfields, 0, len(hopfields)) decreases -pure func CurrSegWithInfo(hopfields []byte, currHfIdx int, SegLen int, inf io.AbsInfoField) io.Seg { +pure func CurrSegWithInfo(hopfields seq[byte], currHfIdx int, SegLen int, inf io.AbsInfoField) io.Seg { return segment(hopfields, 0, currHfIdx, inf.AInfo, inf.UInfo, inf.ConsDir, inf.Peer, SegLen) } // LeftSegWithInfo returns the abstract representation of the next segment of a packet. -// Unlike LeftSeg, it relies solely on the hopfields byte slice and an infofield instead of -// the entire bytes of the packet. Whenever the return value is not none, LeftSegWithInfo -// requires permissions to the hopfields byte slice of the segment specified by currInfIdx. +// Unlike LeftSeg, it relies solely on the view of the hopfields of the segment and an +// infofield instead of the view of the entire packet. Whenever the return value is not +// none, LeftSegWithInfo requires the bytes of the hopfields of the segment specified +// by currInfIdx. ghost opaque requires segs.Valid() @@ -240,11 +328,10 @@ requires (currInfIdx == 1 && segs.Seg2Len > 0) || let start := HopfieldsStartIdx(currInfIdx, segs) in let end := HopfieldsEndIdx(currInfIdx, segs) in inf != none[io.AbsInfoField] && - len(hopfields) == end - start && - sl.Bytes(hopfields, 0, len(hopfields)) + len(hopfields) == end - start decreases pure func LeftSegWithInfo( - hopfields []byte, + hopfields seq[byte], currInfIdx int, segs io.SegLens, inf option[io.AbsInfoField]) option[io.Seg] { @@ -256,9 +343,10 @@ pure func LeftSegWithInfo( } // RightSegWithInfo returns the abstract representation of the previous segment of a packet. -// Unlike RightSeg, it relies solely on the hopfields byte slice and an infofield instead of -// the entire bytes of the packet. Whenever the return value is not none, RightSegWithInfo -// requires permissions to the hopfields byte slice of the segment specified by currInfIdx. +// Unlike RightSeg, it relies solely on the view of the hopfields of the segment and an +// infofield instead of the view of the entire packet. Whenever the return value is not +// none, RightSegWithInfo requires the bytes of the hopfields of the segment specified +// by currInfIdx. ghost opaque requires segs.Valid() @@ -267,11 +355,10 @@ requires (currInfIdx == 0 && segs.Seg2Len > 0) || let start := HopfieldsStartIdx(currInfIdx, segs) in let end := HopfieldsEndIdx(currInfIdx, segs) in inf != none[io.AbsInfoField] && - len(hopfields) == end - start && - sl.Bytes(hopfields, 0, len(hopfields)) + len(hopfields) == end - start decreases pure func RightSegWithInfo( - hopfields []byte, + hopfields seq[byte], currInfIdx int, segs io.SegLens, inf option[io.AbsInfoField]) option[io.Seg] { @@ -283,9 +370,10 @@ pure func RightSegWithInfo( } // MidSegWithInfo returns the abstract representation of the last or first segment of a packet. -// Unlike MidSeg, it relies solely on the hopfields byte slice and an infofield instead of -// the entire bytes of the packet. Whenever the return value is not none, MidSegWithInfo -// requires permissions to the hopfields byte slice of the segment specified by currInfIdx. +// Unlike MidSeg, it relies solely on the view of the hopfields of the segment and an +// infofield instead of the view of the entire packet. Whenever the return value is not +// none, MidSegWithInfo requires the bytes of the hopfields of the segment specified +// by currInfIdx. ghost opaque requires segs.Valid() @@ -294,11 +382,10 @@ requires (segs.Seg2Len > 0 && segs.Seg3Len > 0 && let start := HopfieldsStartIdx(currInfIdx, segs) in let end := HopfieldsEndIdx(currInfIdx, segs) in inf != none[io.AbsInfoField] && - len(hopfields) == end - start && - sl.Bytes(hopfields, 0, len(hopfields)) + len(hopfields) == end - start decreases pure func MidSegWithInfo( - hopfields []byte, + hopfields seq[byte], currInfIdx int, segs io.SegLens, inf option[io.AbsInfoField]) option[io.Seg] { @@ -312,46 +399,32 @@ pure func MidSegWithInfo( // CurrSegEquality ensures that the two definitions of abstract segments, CurrSegWithInfo(..) // and CurrSeg(..), represent the same abstract segment. ghost -requires path.InfoFieldOffset(currInfIdx, MetaLen) + path.InfoLen <= offset -requires 0 < SegLen -requires offset + path.HopLen * SegLen <= len(raw) -requires 0 <= currHfIdx && currHfIdx <= SegLen -requires 0 <= currInfIdx && currInfIdx < 3 -preserves acc(sl.Bytes(raw, 0, len(raw)), R50) -preserves acc(sl.Bytes(raw[offset:offset + SegLen * path.HopLen], 0, SegLen * path.HopLen), R50) -preserves acc(sl.Bytes(InfofieldByteSlice(raw, currInfIdx), 0, path.InfoLen), R50) -ensures let inf := path.BytesToAbsInfoField(InfofieldByteSlice(raw, currInfIdx), 0) in +requires path.InfoFieldOffset(currInfIdx, MetaLen) + path.InfoLen <= offset +requires 0 < SegLen +requires offset + path.HopLen * SegLen <= len(raw) +requires 0 <= currHfIdx && currHfIdx <= SegLen +requires 0 <= currInfIdx && currInfIdx < 3 +ensures let inf := path.BytesToAbsInfoField(InfofieldByteSeq(raw, currInfIdx)) in CurrSegWithInfo(raw[offset:offset + SegLen * path.HopLen], currHfIdx, SegLen, inf) == CurrSeg(raw, offset, currInfIdx, currHfIdx, SegLen, MetaLen) decreases -func CurrSegEquality(raw []byte, offset int, currInfIdx int, currHfIdx int, SegLen int) { - infoBytes := InfofieldByteSlice(raw, currInfIdx) - inf := reveal path.BytesToAbsInfoField(infoBytes, 0) +func CurrSegEquality(raw seq[byte], offset int, currInfIdx int, currHfIdx int, SegLen int) { + infoBytes := InfofieldByteSeq(raw, currInfIdx) + inf := reveal path.BytesToAbsInfoField(infoBytes) infOffset := path.InfoFieldOffset(currInfIdx, MetaLen) - unfold acc(sl.Bytes(raw, 0, len(raw)), R56) - unfold acc(sl.Bytes(infoBytes, 0, path.InfoLen), R56) - path.BytesToAbsInfoFieldOffsetEq(raw, infOffset) - assert path.BytesToAbsInfoField(raw, infOffset) == - path.BytesToAbsInfoField(infoBytes, 0) - sl.AssertSliceOverlap(raw, infOffset, offset + SegLen * path.HopLen) + assert infoBytes == InfofieldBytes(raw, currInfIdx, MetaLen) currseg1 := reveal CurrSeg(raw, offset, currInfIdx, currHfIdx, SegLen, MetaLen) currseg2 := reveal CurrSegWithInfo(raw[offset:offset + SegLen * path.HopLen], currHfIdx, SegLen, inf) - // Establish equality of AInfo - sl.AssertSliceOverlap(raw, infOffset+2, infOffset+4) - sl.AssertSliceOverlap(raw, infOffset+4, infOffset+8) - _ := reveal path.BytesToAbsInfoField(raw, infOffset) - assert currseg1.AInfo == path.Timestamp(raw, currInfIdx, MetaLen) + // Establish equality of the infofield-derived fields + assert currseg1.AInfo == path.Timestamp(infoBytes) assert currseg2.AInfo == inf.AInfo assert currseg1.AInfo == currseg2.AInfo - - // Establish equality of Peer - assert currseg1.Peer == path.Peer(raw, currInfIdx, MetaLen) + assert currseg1.Peer == path.Peer(infoBytes) assert currseg2.Peer == inf.Peer assert currseg1.Peer == currseg2.Peer - fold acc(sl.Bytes(raw, 0, len(raw)), R56) - fold acc(sl.Bytes(infoBytes, 0, path.InfoLen), R56) + // Establish equality of the hopfields widenSegment(raw, offset, currHfIdx, inf.AInfo, inf.UInfo, inf.ConsDir, inf.Peer, SegLen, offset, offset + SegLen * path.HopLen) } @@ -359,14 +432,13 @@ func CurrSegEquality(raw []byte, offset int, currInfIdx int, currHfIdx int, SegL // UpdateCurrSegInfo proves that updating the infofield from inf1 to inf2 does not alter the hopfields // of the current segment. ghost -requires 0 < SegLen -requires 0 <= currHfIdx && currHfIdx <= SegLen -requires SegLen * path.HopLen == len(raw) -preserves acc(sl.Bytes(raw, 0, len(raw)), R50) -ensures CurrSegWithInfo(raw, currHfIdx, SegLen, inf1).UpdateCurrSeg(inf2) == +requires 0 < SegLen +requires 0 <= currHfIdx && currHfIdx <= SegLen +requires SegLen * path.HopLen == len(raw) +ensures CurrSegWithInfo(raw, currHfIdx, SegLen, inf1).UpdateCurrSeg(inf2) == CurrSegWithInfo(raw, currHfIdx, SegLen, inf2) decreases -func UpdateCurrSegInfo(raw []byte, currHfIdx int, SegLen int, +func UpdateCurrSegInfo(raw seq[byte], currHfIdx int, SegLen int, inf1 io.AbsInfoField, inf2 io.AbsInfoField) { seg1 := reveal CurrSegWithInfo(raw, currHfIdx, SegLen, inf1) seg2 := reveal CurrSegWithInfo(raw, currHfIdx, SegLen, inf2) @@ -379,58 +451,42 @@ ghost requires segs.Valid() requires PktLen(segs, MetaLen) <= len(raw) requires 1 <= currInfIdx && currInfIdx < 4 -requires sl.Bytes(raw, 0, len(raw)) -requires (currInfIdx == 1 && segs.Seg2Len > 0) || - (currInfIdx == 2 && segs.Seg2Len > 0 && segs.Seg3Len > 0) ==> - let infoBytes := InfofieldByteSlice(raw, currInfIdx) in - let hopBytes := HopfieldsByteSlice(raw, currInfIdx, segs) in - sl.Bytes(infoBytes, 0, path.InfoLen) && - sl.Bytes(hopBytes, 0, len(hopBytes)) decreases -pure func LeftSegEqualitySpec(raw []byte, currInfIdx int, segs io.SegLens) bool { +pure func LeftSegEqualitySpec(raw seq[byte], currInfIdx int, segs io.SegLens) bool { return (currInfIdx == 1 && segs.Seg2Len > 0) || (currInfIdx == 2 && segs.Seg2Len > 0 && segs.Seg3Len > 0) ? - let infoBytes := InfofieldByteSlice(raw, currInfIdx) in - let hopBytes := HopfieldsByteSlice(raw, currInfIdx, segs) in - let inf := some(path.BytesToAbsInfoField(infoBytes, 0)) in + let infoBytes := InfofieldByteSeq(raw, currInfIdx) in + let hopBytes := HopfieldsByteSeq(raw, currInfIdx, segs) in + let inf := some(path.BytesToAbsInfoField(infoBytes)) in LeftSeg(raw, currInfIdx, segs, MetaLen) == LeftSegWithInfo(hopBytes, currInfIdx, segs, inf) : LeftSeg(raw, currInfIdx, segs, MetaLen) == - LeftSegWithInfo(nil, currInfIdx, segs, none[io.AbsInfoField]) + LeftSegWithInfo(seq[byte]{}, currInfIdx, segs, none[io.AbsInfoField]) } // LeftSegEquality ensures that the two definitions of abstract segments, LeftSegWithInfo(..) // and LeftSeg(..), represent the same abstract segment. // The left segment corresponds to different segments of the packet depending on the currInfIdx. -// To address this, we need to consider all possible cases of currInfIdx. This results in fairly -// complex preconditions and postconditions because, for every currInfIdx, we need an offset for -// its infofield and one for its hopfields. +// To address this, we need to consider all possible cases of currInfIdx. ghost -requires segs.Valid() -requires PktLen(segs, MetaLen) <= len(raw) -requires 1 <= currInfIdx && currInfIdx < 4 -preserves acc(sl.Bytes(raw, 0, len(raw)), R49) -preserves (currInfIdx == 1 && segs.Seg2Len > 0) || - (currInfIdx == 2 && segs.Seg2Len > 0 && segs.Seg3Len > 0) ==> - let infoBytes := InfofieldByteSlice(raw, currInfIdx) in - let hopBytes := HopfieldsByteSlice(raw, currInfIdx, segs) in - acc(sl.Bytes(infoBytes, 0, path.InfoLen), R49) && - acc(sl.Bytes(hopBytes, 0, len(hopBytes)), R49) -ensures LeftSegEqualitySpec(raw, currInfIdx, segs) +requires segs.Valid() +requires PktLen(segs, MetaLen) <= len(raw) +requires 1 <= currInfIdx && currInfIdx < 4 +ensures LeftSegEqualitySpec(raw, currInfIdx, segs) decreases -func LeftSegEquality(raw []byte, currInfIdx int, segs io.SegLens) { +func LeftSegEquality(raw seq[byte], currInfIdx int, segs io.SegLens) { reveal LeftSeg(raw, currInfIdx, segs, MetaLen) if ((currInfIdx == 1 && segs.Seg2Len > 0) || (currInfIdx == 2 && segs.Seg2Len > 0 && segs.Seg3Len > 0)) { - infoBytes := InfofieldByteSlice(raw, currInfIdx) - hopBytes := HopfieldsByteSlice(raw, currInfIdx, segs) - inf := some(reveal path.BytesToAbsInfoField(infoBytes, 0)) + infoBytes := InfofieldByteSeq(raw, currInfIdx) + hopBytes := HopfieldsByteSeq(raw, currInfIdx, segs) + inf := some(reveal path.BytesToAbsInfoField(infoBytes)) offset := HopfieldsStartIdx(currInfIdx, segs) segLen := currInfIdx == 1 ? segs.Seg2Len : segs.Seg3Len reveal LeftSegWithInfo(hopBytes, currInfIdx, segs, inf) CurrSegEquality(raw, offset, currInfIdx, 0, segLen) } else { - reveal LeftSegWithInfo(nil, currInfIdx, segs, none[io.AbsInfoField]) + reveal LeftSegWithInfo(seq[byte]{}, currInfIdx, segs, none[io.AbsInfoField]) } } @@ -440,58 +496,42 @@ ghost requires segs.Valid() requires PktLen(segs, MetaLen) <= len(raw) requires -1 <= currInfIdx && currInfIdx < 2 -requires sl.Bytes(raw, 0, len(raw)) -requires (currInfIdx == 0 && segs.Seg2Len > 0) || - (currInfIdx == 1 && segs.Seg2Len > 0 && segs.Seg3Len > 0) ==> - let infoBytes := InfofieldByteSlice(raw, currInfIdx) in - let hopBytes := HopfieldsByteSlice(raw, currInfIdx, segs) in - sl.Bytes(infoBytes, 0, path.InfoLen) && - sl.Bytes(hopBytes, 0, len(hopBytes)) decreases -pure func RightSegEqualitySpec(raw []byte, currInfIdx int, segs io.SegLens) bool { +pure func RightSegEqualitySpec(raw seq[byte], currInfIdx int, segs io.SegLens) bool { return (currInfIdx == 0 && segs.Seg2Len > 0) || (currInfIdx == 1 && segs.Seg2Len > 0 && segs.Seg3Len > 0) ? - let infoBytes := InfofieldByteSlice(raw, currInfIdx) in - let hopBytes := HopfieldsByteSlice(raw, currInfIdx, segs) in - let inf := some(path.BytesToAbsInfoField(infoBytes, 0)) in + let infoBytes := InfofieldByteSeq(raw, currInfIdx) in + let hopBytes := HopfieldsByteSeq(raw, currInfIdx, segs) in + let inf := some(path.BytesToAbsInfoField(infoBytes)) in RightSeg(raw, currInfIdx, segs, MetaLen) == RightSegWithInfo(hopBytes, currInfIdx, segs, inf) : RightSeg(raw, currInfIdx, segs, MetaLen) == - RightSegWithInfo(nil, currInfIdx, segs, none[io.AbsInfoField]) + RightSegWithInfo(seq[byte]{}, currInfIdx, segs, none[io.AbsInfoField]) } // RightSegEquality ensures that the two definitions of abstract segments, RightSegWithInfo(..) // and RightSeg(..), represent the same abstract segment. // The right segment corresponds to different segments of the packet depending on the currInfIdx. -// To address this, we need to consider all possible cases of currInfIdx. This results in fairly -// complex preconditions and postconditions because, for every currInfIdx, we need an offset for -// its infofield and one for its hopfields. +// To address this, we need to consider all possible cases of currInfIdx. ghost -requires segs.Valid() -requires PktLen(segs, MetaLen) <= len(raw) -requires -1 <= currInfIdx && currInfIdx < 2 -preserves acc(sl.Bytes(raw, 0, len(raw)), R49) -preserves (currInfIdx == 0 && segs.Seg2Len > 0) || - (currInfIdx == 1 && segs.Seg2Len > 0 && segs.Seg3Len > 0) ==> - let infoBytes := InfofieldByteSlice(raw, currInfIdx) in - let hopBytes := HopfieldsByteSlice(raw, currInfIdx, segs) in - acc(sl.Bytes(infoBytes, 0, path.InfoLen), R49) && - acc(sl.Bytes(hopBytes, 0, len(hopBytes)), R49) -ensures RightSegEqualitySpec(raw, currInfIdx, segs) +requires segs.Valid() +requires PktLen(segs, MetaLen) <= len(raw) +requires -1 <= currInfIdx && currInfIdx < 2 +ensures RightSegEqualitySpec(raw, currInfIdx, segs) decreases -func RightSegEquality(raw []byte, currInfIdx int, segs io.SegLens) { +func RightSegEquality(raw seq[byte], currInfIdx int, segs io.SegLens) { reveal RightSeg(raw, currInfIdx, segs, MetaLen) if ((currInfIdx == 0 && segs.Seg2Len > 0) || (currInfIdx == 1 && segs.Seg2Len > 0 && segs.Seg3Len > 0)) { - infoBytes := InfofieldByteSlice(raw, currInfIdx) - hopBytes := HopfieldsByteSlice(raw, currInfIdx, segs) - inf := some(reveal path.BytesToAbsInfoField(infoBytes, 0)) + infoBytes := InfofieldByteSeq(raw, currInfIdx) + hopBytes := HopfieldsByteSeq(raw, currInfIdx, segs) + inf := some(reveal path.BytesToAbsInfoField(infoBytes)) offset := HopfieldsStartIdx(currInfIdx, segs) segLen := currInfIdx == 0 ? segs.Seg1Len : segs.Seg2Len reveal RightSegWithInfo(hopBytes, currInfIdx, segs, inf) CurrSegEquality(raw, offset, currInfIdx, segLen, segLen) } else { - reveal RightSegWithInfo(nil, currInfIdx, segs, none[io.AbsInfoField]) + reveal RightSegWithInfo(seq[byte]{}, currInfIdx, segs, none[io.AbsInfoField]) } } @@ -501,63 +541,47 @@ ghost requires segs.Valid() requires PktLen(segs, MetaLen) <= len(raw) requires 2 <= currInfIdx && currInfIdx < 5 -requires sl.Bytes(raw, 0, len(raw)) -requires (segs.Seg2Len > 0 && segs.Seg3Len > 0 && - (currInfIdx == 2 || currInfIdx == 4)) ==> - let infoBytes := InfofieldByteSlice(raw, currInfIdx) in - let hopBytes := HopfieldsByteSlice(raw, currInfIdx, segs) in - sl.Bytes(infoBytes, 0, path.InfoLen) && - sl.Bytes(hopBytes, 0, len(hopBytes)) decreases -pure func MidSegEqualitySpec(raw []byte, currInfIdx int, segs io.SegLens) bool { +pure func MidSegEqualitySpec(raw seq[byte], currInfIdx int, segs io.SegLens) bool { return (segs.Seg2Len > 0 && segs.Seg3Len > 0 && (currInfIdx == 2 || currInfIdx == 4)) ? - let infoBytes := InfofieldByteSlice(raw, currInfIdx) in - let hopBytes := HopfieldsByteSlice(raw, currInfIdx, segs) in - let inf := some(path.BytesToAbsInfoField(infoBytes, 0)) in + let infoBytes := InfofieldByteSeq(raw, currInfIdx) in + let hopBytes := HopfieldsByteSeq(raw, currInfIdx, segs) in + let inf := some(path.BytesToAbsInfoField(infoBytes)) in MidSeg(raw, currInfIdx, segs, MetaLen) == MidSegWithInfo(hopBytes, currInfIdx, segs, inf) : MidSeg(raw, currInfIdx, segs, MetaLen) == - MidSegWithInfo(nil, currInfIdx, segs, none[io.AbsInfoField]) + MidSegWithInfo(seq[byte]{}, currInfIdx, segs, none[io.AbsInfoField]) } // MidSegEquality ensures that the two definitions of abstract segments, MidSegWithInfo(..) // and MidSeg(..), represent the same abstract segment. // The mid segment corresponds to different segments of the packet depending on the currInfIdx. -// To address this, we need to consider all possible cases of currInfIdx. This results in fairly -// complex preconditions and postconditions because, for every currInfIdx, we need an offset for -// its infofield and one for its hopfields. +// To address this, we need to consider all possible cases of currInfIdx. ghost -requires segs.Valid() -requires PktLen(segs, MetaLen) <= len(raw) -requires 2 <= currInfIdx && currInfIdx < 5 -preserves acc(sl.Bytes(raw, 0, len(raw)), R49) -preserves (segs.Seg2Len > 0 && segs.Seg3Len > 0 && - (currInfIdx == 2 || currInfIdx == 4)) ==> - let infoBytes := InfofieldByteSlice(raw, currInfIdx) in - let hopBytes := HopfieldsByteSlice(raw, currInfIdx, segs) in - acc(sl.Bytes(infoBytes, 0, path.InfoLen), R49) && - acc(sl.Bytes(hopBytes, 0, len(hopBytes)), R49) -ensures MidSegEqualitySpec(raw, currInfIdx, segs) +requires segs.Valid() +requires PktLen(segs, MetaLen) <= len(raw) +requires 2 <= currInfIdx && currInfIdx < 5 +ensures MidSegEqualitySpec(raw, currInfIdx, segs) decreases -func MidSegEquality(raw []byte, currInfIdx int, segs io.SegLens) { +func MidSegEquality(raw seq[byte], currInfIdx int, segs io.SegLens) { reveal MidSeg(raw, currInfIdx, segs, MetaLen) if (currInfIdx == 4 && segs.Seg2Len > 0 && segs.Seg3Len > 0) { - infoBytes := InfofieldByteSlice(raw, 0) - hopBytes := HopfieldsByteSlice(raw, 0, segs) - inf := some(reveal path.BytesToAbsInfoField(infoBytes, 0)) + infoBytes := InfofieldByteSeq(raw, 0) + hopBytes := HopfieldsByteSeq(raw, 0, segs) + inf := some(reveal path.BytesToAbsInfoField(infoBytes)) offset := HopfieldsStartIdx(currInfIdx, segs) reveal MidSegWithInfo(hopBytes, currInfIdx, segs, inf) CurrSegEquality(raw, offset, 0, segs.Seg1Len, segs.Seg1Len) } else if (currInfIdx == 2 && segs.Seg2Len > 0 && segs.Seg3Len > 0) { - infoBytes := InfofieldByteSlice(raw, currInfIdx) - hopBytes := HopfieldsByteSlice(raw, currInfIdx, segs) - inf := some(reveal path.BytesToAbsInfoField(infoBytes, 0)) + infoBytes := InfofieldByteSeq(raw, currInfIdx) + hopBytes := HopfieldsByteSeq(raw, currInfIdx, segs) + inf := some(reveal path.BytesToAbsInfoField(infoBytes)) offset := HopfieldsStartIdx(currInfIdx, segs) reveal MidSegWithInfo(hopBytes, currInfIdx, segs, inf) CurrSegEquality(raw, offset, currInfIdx, 0, segs.Seg3Len) } else { - reveal MidSegWithInfo(nil, currInfIdx, segs, none[io.AbsInfoField]) + reveal MidSegWithInfo(seq[byte]{}, currInfIdx, segs, none[io.AbsInfoField]) } } @@ -567,56 +591,90 @@ func MidSegEquality(raw []byte, currInfIdx int, segs io.SegLens) { ghost requires 0 <= currHfIdx && currHfIdx < segLen requires segLen * path.HopLen == len(hopfields) -requires sl.Bytes(hopfields, 0, len(hopfields)) -requires let currHfStart := currHfIdx * path.HopLen in - let currHfEnd := currHfStart + path.HopLen in - sl.Bytes(hopfields[:currHfStart], 0, currHfStart) && - sl.Bytes(hopfields[currHfStart:currHfEnd], 0, path.HopLen) && - sl.Bytes(hopfields[currHfEnd:], 0, (segLen - currHfIdx - 1) * path.HopLen) decreases -pure func BytesStoreCurrSeg(hopfields []byte, currHfIdx int, segLen int, inf io.AbsInfoField) bool { +pure func BytesStoreCurrSeg(hopfields seq[byte], currHfIdx int, segLen int, inf io.AbsInfoField) bool { return let currseg := CurrSegWithInfo(hopfields, currHfIdx, segLen, inf) in let currHfStart := currHfIdx * path.HopLen in let currHfEnd := currHfStart + path.HopLen in len(currseg.Future) > 0 && - currseg.Future[0] == path.BytesToIO_HF(hopfields[currHfStart:currHfEnd], 0, 0, path.HopLen) && - currseg.Future[1:] == hopFields(hopfields[currHfEnd:], 0, 0, (segLen - currHfIdx - 1)) && - currseg.Past == segPast(hopFields(hopfields[:currHfStart], 0, 0, currHfIdx)) && - currseg.History == segHistory(hopFields(hopfields[:currHfStart], 0, 0, currHfIdx)) && + currseg.Future[0] == path.BytesToIO_HF(hopfields[currHfStart:currHfEnd]) && + currseg.Future[1:] == hopFields(hopfields[currHfEnd:], 0, 0, (segLen - currHfIdx - 1)) && + currseg.Past == segPast(hopFields(hopfields[:currHfStart], 0, 0, currHfIdx)) && + currseg.History == segHistory(hopFields(hopfields[:currHfStart], 0, 0, currHfIdx)) && currseg.AInfo == inf.AInfo && currseg.UInfo == inf.UInfo && currseg.ConsDir == inf.ConsDir && currseg.Peer == inf.Peer } -// `EstablishBytesStoreCurrSeg` shows that the raw bytes containing all hopfields -// can be split into three slices, one that exclusively contains all past hopfields, one +// `EstablishBytesStoreCurrSeg` shows that the sequence of bytes containing all hopfields +// can be split into three subsequences, one that exclusively contains all past hopfields, one // that exclusively contains all future ones and another one for the current hopfield. // This helps in proving that the future and past hopfields remain unchanged when the // current hopfield is modified. ghost requires 0 <= currHfIdx && currHfIdx < segLen requires segLen * path.HopLen == len(hopfields) -preserves acc(sl.Bytes(hopfields, 0, len(hopfields)), R49) -preserves let currHfStart := currHfIdx * path.HopLen in - let currHfEnd := currHfStart + path.HopLen in - acc(sl.Bytes(hopfields[:currHfStart], 0, currHfStart), R49) && - acc(sl.Bytes(hopfields[currHfStart:currHfEnd], 0, path.HopLen), R49) && - acc(sl.Bytes(hopfields[currHfEnd:], 0, (segLen - currHfIdx - 1) * path.HopLen), R49) ensures BytesStoreCurrSeg(hopfields, currHfIdx, segLen, inf) decreases -func EstablishBytesStoreCurrSeg(hopfields []byte, currHfIdx int, segLen int, inf io.AbsInfoField) { +func EstablishBytesStoreCurrSeg(hopfields seq[byte], currHfIdx int, segLen int, inf io.AbsInfoField) { currseg := reveal CurrSegWithInfo(hopfields, currHfIdx, segLen, inf) currHfStart := currHfIdx * path.HopLen currHfEnd := currHfStart + path.HopLen - HopsFromSuffixOfRawMatchSuffixOfHops(hopfields, 0, 0, segLen, currHfIdx) - AlignHopsOfRawWithOffsetAndIndex(hopfields, 0, currHfIdx + 1, segLen, currHfIdx + 1) - HopsFromPrefixOfRawMatchPrefixOfHops(hopfields, 0, 0, segLen, currHfIdx + 1) + establishCurrSegFutureHead(hopfields, currHfIdx, segLen) + establishCurrSegFutureTail(hopfields, currHfIdx, segLen) + establishCurrSegPast(hopfields, currHfIdx, segLen) + assert currseg.Future == hopFields(hopfields, 0, 0, segLen)[currHfIdx:] + assert currseg.Past == segPast(hopFields(hopfields[:currHfStart], 0, 0, currHfIdx)) + assert currseg.History == segHistory(hopFields(hopfields[:currHfStart], 0, 0, currHfIdx)) +} + +// establishCurrSegFutureHead relates the head of the future hopfields +// of the current segment to the serialization of the current hopfield. +ghost +requires 0 <= currHfIdx && currHfIdx < segLen +requires segLen * path.HopLen == len(hopfields) +ensures hopFields(hopfields, 0, 0, segLen)[currHfIdx:] == + hopFields(hopfields, 0, currHfIdx, segLen) +ensures hopFields(hopfields, 0, 0, segLen)[currHfIdx:][0] == + path.BytesToIO_HF(hopfields[currHfIdx * path.HopLen : currHfIdx * path.HopLen + path.HopLen]) +decreases +func establishCurrSegFutureHead(hopfields seq[byte], currHfIdx int, segLen int) { HopsFromPrefixOfRawMatchPrefixOfHops(hopfields, 0, 0, segLen, currHfIdx) - widenHopFields(hopfields, 0, 0, currHfIdx, 0, currHfStart, R52) - widenHopFields(hopfields, currHfEnd, 0, segLen - currHfIdx - 1, currHfEnd, segLen * path.HopLen, R52) - widenHopFields(hopfields, currHfStart, 0, 1, currHfStart, currHfEnd, R52) + assert hopFields(hopfields, 0, currHfIdx, segLen)[0] == + path.BytesToIO_HF(hopfields[currHfIdx * path.HopLen : currHfIdx * path.HopLen + path.HopLen]) +} + +// establishCurrSegFutureTail relates the tail of the future hopfields +// of the current segment to the bytes that follow the current hopfield. +ghost +requires 0 <= currHfIdx && currHfIdx < segLen +requires segLen * path.HopLen == len(hopfields) +ensures hopFields(hopfields, 0, 0, segLen)[currHfIdx:][1:] == + hopFields(hopfields[currHfIdx * path.HopLen + path.HopLen:], 0, 0, segLen - currHfIdx - 1) +decreases +func establishCurrSegFutureTail(hopfields seq[byte], currHfIdx int, segLen int) { + currHfEnd := currHfIdx * path.HopLen + path.HopLen + HopsFromPrefixOfRawMatchPrefixOfHops(hopfields, 0, 0, segLen, currHfIdx + 1) + assert hopFields(hopfields, 0, 0, segLen)[currHfIdx:][1:] == + hopFields(hopfields, 0, 0, segLen)[currHfIdx + 1:] + AlignHopsOfRawWithOffsetAndIndex(hopfields, 0, currHfIdx + 1, segLen, currHfIdx + 1) + widenHopFields(hopfields, currHfEnd, 0, segLen - currHfIdx - 1, currHfEnd, segLen * path.HopLen) + assert hopfields[currHfEnd:] == hopfields[currHfEnd:segLen * path.HopLen] +} + +// establishCurrSegPast relates the past hopfields of the current +// segment to the bytes that precede the current hopfield. +ghost +requires 0 <= currHfIdx && currHfIdx < segLen +requires segLen * path.HopLen == len(hopfields) +ensures hopFields(hopfields, 0, 0, segLen)[:currHfIdx] == + hopFields(hopfields[:currHfIdx * path.HopLen], 0, 0, currHfIdx) +decreases +func establishCurrSegPast(hopfields seq[byte], currHfIdx int, segLen int) { + HopsFromSuffixOfRawMatchSuffixOfHops(hopfields, 0, 0, segLen, currHfIdx) + widenHopFields(hopfields, 0, 0, currHfIdx, 0, currHfIdx * path.HopLen) } // `SplitHopfields` splits the permission to the raw bytes of a segment into the permission @@ -632,6 +690,14 @@ ensures let currHfStart := currHfIdx * path.HopLen in acc(sl.Bytes(hopfields[:currHfStart], 0, currHfStart), p) && acc(sl.Bytes(hopfields[currHfStart:currHfEnd], 0, path.HopLen), p) && acc(sl.Bytes(hopfields[currHfEnd:], 0, (segLen - currHfIdx - 1) * path.HopLen), p) +ensures let currHfStart := currHfIdx * path.HopLen in + let currHfEnd := currHfStart + path.HopLen in + sl.View(hopfields[:currHfStart], 0, currHfStart) == + old(sl.View(hopfields, 0, len(hopfields)))[:currHfStart] && + sl.View(hopfields[currHfStart:currHfEnd], 0, path.HopLen) == + old(sl.View(hopfields, 0, len(hopfields)))[currHfStart:currHfEnd] && + sl.View(hopfields[currHfEnd:], 0, (segLen - currHfIdx - 1) * path.HopLen) == + old(sl.View(hopfields, 0, len(hopfields)))[currHfEnd:] decreases func SplitHopfields(hopfields []byte, currHfIdx int, segLen int, p perm) { currHfStart := currHfIdx * path.HopLen @@ -656,6 +722,10 @@ requires let currHfStart := currHfIdx * path.HopLen in acc(sl.Bytes(hopfields[currHfStart:currHfEnd], 0, path.HopLen), p) && acc(sl.Bytes(hopfields[currHfEnd:], 0, (segLen - currHfIdx - 1) * path.HopLen), p) ensures acc(sl.Bytes(hopfields, 0, len(hopfields)), p) +ensures let currHfStart := currHfIdx * path.HopLen in + let currHfEnd := currHfStart + path.HopLen in + sl.View(hopfields, 0, len(hopfields)) == + old(sl.View(hopfields[:currHfStart], 0, currHfStart)) ++ old(sl.View(hopfields[currHfStart:currHfEnd], 0, path.HopLen)) ++ old(sl.View(hopfields[currHfEnd:], 0, (segLen - currHfIdx - 1) * path.HopLen)) decreases func CombineHopfields(hopfields []byte, currHfIdx int, segLen int, p perm) { currHfStart := currHfIdx * path.HopLen @@ -665,4 +735,4 @@ func CombineHopfields(hopfields []byte, currHfIdx int, segLen int, p perm) { sl.Unslice_Bytes(hopfields, 0, currHfStart, p) sl.CombineAtIndex_Bytes(hopfields, currHfStart, len(hopfields), currHfEnd, p) sl.CombineAtIndex_Bytes(hopfields, 0, len(hopfields), currHfStart, p) -} \ No newline at end of file +} diff --git a/pkg/slayers/path/scion/raw.go b/pkg/slayers/path/scion/raw.go index 9947c338e..2199761bd 100644 --- a/pkg/slayers/path/scion/raw.go +++ b/pkg/slayers/path/scion/raw.go @@ -39,7 +39,7 @@ type Raw struct { // @ ensures res == nil ==> s.Mem(data) // @ ensures res == nil ==> // @ s.GetBase(data).WeaklyValid() && -// @ s.GetBase(data).EqAbsHeader(data) +// @ s.GetBase(data).EqAbsHeader(sl.View(data, 0, len(data))) // @ ensures res != nil ==> (s.NonInitMem() && res.ErrorMem()) // @ decreases func (s *Raw) DecodeFromBytes(data []byte) (res error) { @@ -161,41 +161,33 @@ func (s *Raw) ToDecoded( /*@ ghost ubuf []byte @*/ ) (d *Decoded, err error) { // @ Unreachable() return nil, err } - //@ ghost b0 := (unfolding acc(sl.Bytes(s.Raw[:MetaLen], 0, MetaLen), _) in s.Raw[0]) - //@ ghost b1 := (unfolding acc(sl.Bytes(s.Raw[:MetaLen], 0, MetaLen), _) in s.Raw[1]) - //@ ghost b2 := (unfolding acc(sl.Bytes(s.Raw[:MetaLen], 0, MetaLen), _) in s.Raw[2]) - //@ ghost b3 := (unfolding acc(sl.Bytes(s.Raw[:MetaLen], 0, MetaLen), _) in s.Raw[3]) + // The postcondition of SerializeTo speaks about the view of the + // serialized buffer, so the serialized bytes are captured from that + // view; the split and combine lemmas below relate it to the views + // of the other instances, with no reasoning about raw byte values. + //@ ghost vMeta := sl.View(s.Raw[:MetaLen], 0, MetaLen) + //@ ghost b0 := vMeta[0] + //@ ghost b1 := vMeta[1] + //@ ghost b2 := vMeta[2] + //@ ghost b3 := vMeta[3] //@ assert let line := s.PathMeta.SerializedToLine() in binary.BigEndian.PutUint32Spec(b0, b1, b2, b3, line) - //@ sl.CombineRange_Bytes(ubuf, 0, MetaLen, HalfPerm) - //@ assert &ubuf[0] == &s.Raw[:MetaLen][0] - //@ assert &ubuf[1] == &s.Raw[:MetaLen][1] - //@ assert &ubuf[2] == &s.Raw[:MetaLen][2] - //@ assert &ubuf[3] == &s.Raw[:MetaLen][3] - //@ assert b0 == (unfolding acc(sl.Bytes(s.Raw[:MetaLen], 0, MetaLen), _) in ubuf[0]) - // (VerifiedSCION): for some reason, silicon requires the following line to be able to prove - // bX == ubuf[X]. - //@ assert unfolding acc(sl.Bytes(s.Raw[:MetaLen], 0, MetaLen), _) in - //@ (ubuf[0] == (unfolding acc(sl.Bytes(ubuf, 0, len(ubuf)), _) in ubuf[0])) - //@ sl.CombineRange_Bytes(ubuf, 0, MetaLen, HalfPerm) + //@ assert s.Raw[:MetaLen] === ubuf[:MetaLen] + //@ sl.CombineRangeWithViews_Bytes(ubuf, 0, MetaLen, HalfPerm, sl.View(ubuf, 0, 0), vMeta, sl.View(ubuf, MetaLen, len(ubuf))) + //@ assert sl.View(ubuf, 0, len(ubuf))[0:MetaLen] == vMeta + //@ sl.CombineRangeWithViews_Bytes(ubuf, 0, MetaLen, HalfPerm, sl.View(ubuf, 0, 0), vMeta, sl.View(ubuf, MetaLen, len(ubuf))) + //@ assert sl.View(ubuf, 0, len(ubuf))[0:MetaLen] == vMeta decoded := &Decoded{} //@ fold decoded.Base.NonInitMem() //@ fold decoded.NonInitMem() //@ sl.SplitByIndex_Bytes(ubuf, 0, len(ubuf), len(s.Raw), HalfPerm) - //@ assert unfolding acc(sl.Bytes(ubuf, 0, len(ubuf)), _) in - //@ (ubuf[0] == (unfolding acc(sl.Bytes(ubuf, 0, len(s.Raw)), _) in ubuf[0])) + //@ assert sl.View(ubuf, 0, len(s.Raw))[0:MetaLen] == vMeta //@ sl.SplitByIndex_Bytes(ubuf, 0, len(ubuf), len(s.Raw), HalfPerm) //@ sl.Reslice_Bytes(ubuf, 0, len(s.Raw), HalfPerm) - //@ assert &ubuf[0] == &ubuf[:len(s.Raw)][0] - //@ assert &ubuf[1] == &ubuf[:len(s.Raw)][1] - //@ assert &ubuf[2] == &ubuf[:len(s.Raw)][2] - //@ assert &ubuf[3] == &ubuf[:len(s.Raw)][3] - //@ assert unfolding acc(sl.Bytes(ubuf[:len(s.Raw)], 0, len(s.Raw)), _) in - //@ (ubuf[0] == (unfolding acc(sl.Bytes(ubuf, 0, len(s.Raw)), _) in ubuf[0])) - //@ assert b0 == (unfolding acc(sl.Bytes(ubuf, 0, len(s.Raw)), _) in ubuf[0]) - //@ assert b1 == (unfolding acc(sl.Bytes(ubuf, 0, len(s.Raw)), _) in ubuf[1]) - //@ assert b2 == (unfolding acc(sl.Bytes(ubuf, 0, len(s.Raw)), _) in ubuf[2]) - //@ assert b3 == (unfolding acc(sl.Bytes(ubuf, 0, len(s.Raw)), _) in ubuf[3]) + //@ assert sl.View(ubuf[:len(s.Raw)], 0, len(s.Raw))[0:MetaLen] == vMeta //@ sl.Reslice_Bytes(ubuf, 0, len(s.Raw), HalfPerm) + //@ assert s.Raw === ubuf[:len(s.Raw)] + //@ assert sl.View(s.Raw, 0, len(s.Raw))[0] == b0 && sl.View(s.Raw, 0, len(s.Raw))[1] == b1 + //@ assert sl.View(s.Raw, 0, len(s.Raw))[2] == b2 && sl.View(s.Raw, 0, len(s.Raw))[3] == b3 if err := decoded.DecodeFromBytes(s.Raw); err != nil { //@ sl.Unslice_Bytes(ubuf, 0, len(s.Raw), writePerm) //@ sl.CombineAtIndex_Bytes(ubuf, 0, len(ubuf), len(s.Raw), writePerm) @@ -204,6 +196,19 @@ func (s *Raw) ToDecoded( /*@ ghost ubuf []byte @*/ ) (d *Decoded, err error) { return nil, err } //@ ghost lenR := len(s.Raw) // TODO: move to the top and rewrite body + // the postcondition of decoded.DecodeFromBytes characterizes the + // meta header through GetByte; ViewElems bridges those terms to the + // view elements, which the asserts before the call related to the + // serialized bytes + //@ sl.ViewElems(s.Raw, 0, len(s.Raw), R43) + //@ assert sl.View(s.Raw, 0, len(s.Raw))[0] == sl.GetByte(s.Raw, 0, len(s.Raw), 0) + //@ assert sl.View(s.Raw, 0, len(s.Raw))[1] == sl.GetByte(s.Raw, 0, len(s.Raw), 1) + //@ assert sl.View(s.Raw, 0, len(s.Raw))[2] == sl.GetByte(s.Raw, 0, len(s.Raw), 2) + //@ assert sl.View(s.Raw, 0, len(s.Raw))[3] == sl.GetByte(s.Raw, 0, len(s.Raw), 3) + //@ assert sl.GetByte(s.Raw, 0, len(s.Raw), 0) == b0 + //@ assert sl.GetByte(s.Raw, 0, len(s.Raw), 1) == b1 + //@ assert sl.GetByte(s.Raw, 0, len(s.Raw), 2) == b2 + //@ assert sl.GetByte(s.Raw, 0, len(s.Raw), 3) == b3 //@ ghost if validIdxs { //@ s.PathMeta.SerializeAndDeserializeLemma(b0, b1, b2, b3) //@ assert pathMeta == decoded.GetMetaHdr(s.Raw) @@ -222,11 +227,11 @@ func (s *Raw) ToDecoded( /*@ ghost ubuf []byte @*/ ) (d *Decoded, err error) { // @ requires s.Mem(ubuf) // @ requires sl.Bytes(ubuf, 0, len(ubuf)) // pres for IO: -// @ requires s.GetBase(ubuf).EqAbsHeader(ubuf) -// @ requires validPktMetaHdr(ubuf) -// @ requires s.absPkt(ubuf).PathNotFullyTraversed() +// @ requires s.GetBase(ubuf).EqAbsHeader(sl.View(ubuf, 0, len(ubuf))) +// @ requires validPktMetaHdr(sl.View(ubuf, 0, len(ubuf))) +// @ requires s.absPkt(sl.View(ubuf, 0, len(ubuf))).PathNotFullyTraversed() // @ requires s.GetBase(ubuf).IsXoverSpec() ==> -// @ s.absPkt(ubuf).LeftSeg != none[io.Seg] +// @ s.absPkt(sl.View(ubuf, 0, len(ubuf))).LeftSeg != none[io.Seg] // @ ensures sl.Bytes(ubuf, 0, len(ubuf)) // @ ensures old(unfolding s.Mem(ubuf) in unfolding // @ s.Base.Mem() in (s.NumINF <= 0 || int(s.PathMeta.CurrHF) >= s.NumHops-1)) ==> r != nil @@ -235,11 +240,12 @@ func (s *Raw) ToDecoded( /*@ ghost ubuf []byte @*/ ) (d *Decoded, err error) { // @ ensures r != nil ==> r.ErrorMem() // post for IO: // @ ensures r == nil ==> -// @ s.GetBase(ubuf).EqAbsHeader(ubuf) && validPktMetaHdr(ubuf) +// @ s.GetBase(ubuf).EqAbsHeader(sl.View(ubuf, 0, len(ubuf))) && +// @ validPktMetaHdr(sl.View(ubuf, 0, len(ubuf))) // @ ensures r == nil && old(s.GetBase(ubuf).IsXoverSpec()) ==> -// @ s.absPkt(ubuf) == AbsXover(old(s.absPkt(ubuf))) +// @ s.absPkt(sl.View(ubuf, 0, len(ubuf))) == AbsXover(old(s.absPkt(sl.View(ubuf, 0, len(ubuf))))) // @ ensures r == nil && !old(s.GetBase(ubuf).IsXoverSpec()) ==> -// @ s.absPkt(ubuf) == AbsIncPath(old(s.absPkt(ubuf))) +// @ s.absPkt(sl.View(ubuf, 0, len(ubuf))) == AbsIncPath(old(s.absPkt(sl.View(ubuf, 0, len(ubuf))))) // (VerifiedSCION) the following post is technically redundant, // as it conveys information that could, in principle, be conveyed // with the previous posts. We should at some point revisit all @@ -248,8 +254,10 @@ func (s *Raw) ToDecoded( /*@ ghost ubuf []byte @*/ ) (d *Decoded, err error) { // @ s.GetBase(ubuf) == old(s.GetBase(ubuf).IncPathSpec()) // @ decreases func (s *Raw) IncPath( /*@ ghost ubuf []byte @*/ ) (r error) { + //@ ghost oldView := sl.View(ubuf, 0, len(ubuf)) //@ unfold s.Mem(ubuf) - //@ reveal validPktMetaHdr(ubuf) + //@ reveal validPktMetaHdr(oldView) + //@ ghost tail := oldView[MetaLen:] //@ unfold acc(s.Base.Mem(), R56) //@ oldCurrInfIdx := int(s.PathMeta.CurrINF) //@ oldCurrHfIdx := int(s.PathMeta.CurrHF) @@ -266,47 +274,49 @@ func (s *Raw) IncPath( /*@ ghost ubuf []byte @*/ ) (r error) { return err } //@ fold acc(s.Mem(ubuf), HalfPerm) - //@ sl.SplitRange_Bytes(ubuf, 0, MetaLen, HalfPerm) - //@ ValidPktMetaHdrSublice(ubuf, MetaLen) - //@ sl.Reslice_Bytes(ubuf, MetaLen, len(ubuf), HalfPerm) - //@ tail := ubuf[MetaLen:] - //@ unfold acc(sl.Bytes(tail, 0, len(tail)), R50) //@ oldHfIdxSeg := oldCurrHfIdx-oldPrevSegLen - //@ WidenCurrSeg(ubuf, oldOffset + MetaLen, oldCurrInfIdx, oldHfIdxSeg, oldSegLen, MetaLen, MetaLen, len(ubuf)) - //@ WidenLeftSeg(ubuf, oldCurrInfIdx + 1, oldSegs, MetaLen, MetaLen, len(ubuf)) - //@ WidenMidSeg(ubuf, oldCurrInfIdx + 2, oldSegs, MetaLen, MetaLen, len(ubuf)) - //@ WidenRightSeg(ubuf, oldCurrInfIdx - 1, oldSegs, MetaLen, MetaLen, len(ubuf)) + //@ WidenCurrSeg(oldView, oldOffset + MetaLen, oldCurrInfIdx, oldHfIdxSeg, oldSegLen, MetaLen, MetaLen, len(oldView)) + //@ WidenLeftSeg(oldView, oldCurrInfIdx + 1, oldSegs, MetaLen, MetaLen, len(oldView)) + //@ WidenMidSeg(oldView, oldCurrInfIdx + 2, oldSegs, MetaLen, MetaLen, len(oldView)) + //@ WidenRightSeg(oldView, oldCurrInfIdx - 1, oldSegs, MetaLen, MetaLen, len(oldView)) + //@ assert oldView[MetaLen:len(oldView)] == tail //@ LenCurrSeg(tail, oldOffset, oldCurrInfIdx, oldHfIdxSeg, oldSegLen) - //@ oldAbsPkt := reveal s.absPkt(ubuf) - //@ sl.SplitRange_Bytes(ubuf, 0, MetaLen, HalfPerm) + //@ oldAbsPkt := reveal s.absPkt(oldView) + //@ sl.SplitRange_Bytes(ubuf, 0, MetaLen, writePerm) //@ unfold acc(s.Base.Mem(), R2) err := s.PathMeta.SerializeTo(s.Raw[:MetaLen]) //@ assert s.Base.Valid() //@ assert s.PathMeta.InBounds() - //@ v := s.Raw[:MetaLen] - //@ b0 := sl.GetByte(v, 0, MetaLen, 0) - //@ b1 := sl.GetByte(v, 0, MetaLen, 1) - //@ b2 := sl.GetByte(v, 0, MetaLen, 2) - //@ b3 := sl.GetByte(v, 0, MetaLen, 3) + //@ ghost metaView := sl.View(s.Raw[:MetaLen], 0, MetaLen) + //@ b0 := metaView[0] + //@ b1 := metaView[1] + //@ b2 := metaView[2] + //@ b3 := metaView[3] //@ s.PathMeta.SerializeAndDeserializeLemma(b0, b1, b2, b3) - //@ assert s.PathMeta.EqAbsHeader(v) - //@ assert RawBytesToBase(v).Valid() - //@ sl.CombineRange_Bytes(ubuf, 0, MetaLen, HalfPerm) - //@ ValidPktMetaHdrSublice(ubuf, MetaLen) - //@ assert s.EqAbsHeader(ubuf) == s.PathMeta.EqAbsHeader(ubuf) - //@ assert reveal validPktMetaHdr(ubuf) + //@ assert s.PathMeta.EqAbsHeader(metaView) + //@ sl.CombineRangeWithViews_Bytes(ubuf, 0, MetaLen, writePerm, sl.View(ubuf, 0, 0), sl.View(ubuf[0:MetaLen], 0, (MetaLen)-(0)), sl.View(ubuf, MetaLen, len(ubuf))) + //@ ghost newView := sl.View(ubuf, 0, len(ubuf)) + //@ assert newView[:MetaLen] == metaView + //@ assert newView[MetaLen:] == tail + //@ assert newView[0] == metaView[0] && newView[1] == metaView[1] + //@ assert newView[2] == metaView[2] && newView[3] == metaView[3] + //@ assert s.PathMeta.EqAbsHeader(newView) + //@ assert RawBytesToBase(newView).Valid() + //@ assert s.EqAbsHeader(newView) == s.PathMeta.EqAbsHeader(newView) + //@ assert reveal validPktMetaHdr(newView) //@ currInfIdx := int(s.PathMeta.CurrINF) //@ currHfIdx := int(s.PathMeta.CurrHF) //@ assert currHfIdx == oldCurrHfIdx + 1 //@ ghost if(currInfIdx == oldCurrInfIdx) { //@ IncCurrSeg(tail, oldOffset, oldCurrInfIdx, oldHfIdxSeg, oldSegLen) - //@ WidenCurrSeg(ubuf, oldOffset + MetaLen, oldCurrInfIdx, oldHfIdxSeg + 1, - //@ oldSegLen, MetaLen, MetaLen, len(ubuf)) - //@ WidenLeftSeg(ubuf, oldCurrInfIdx + 1, oldSegs, MetaLen, MetaLen, len(ubuf)) - //@ WidenMidSeg(ubuf, oldCurrInfIdx + 2, oldSegs, MetaLen, MetaLen, len(ubuf)) - //@ WidenRightSeg(ubuf, oldCurrInfIdx - 1, oldSegs, MetaLen, MetaLen, len(ubuf)) - //@ assert reveal s.absPkt(ubuf) == AbsIncPath(oldAbsPkt) + //@ WidenCurrSeg(newView, oldOffset + MetaLen, oldCurrInfIdx, oldHfIdxSeg + 1, + //@ oldSegLen, MetaLen, MetaLen, len(newView)) + //@ WidenLeftSeg(newView, oldCurrInfIdx + 1, oldSegs, MetaLen, MetaLen, len(newView)) + //@ WidenMidSeg(newView, oldCurrInfIdx + 2, oldSegs, MetaLen, MetaLen, len(newView)) + //@ WidenRightSeg(newView, oldCurrInfIdx - 1, oldSegs, MetaLen, MetaLen, len(newView)) + //@ assert newView[MetaLen:len(newView)] == tail + //@ assert reveal s.absPkt(newView) == AbsIncPath(oldAbsPkt) //@ } else { //@ segLen := oldSegs.LengthOfCurrSeg(currHfIdx) //@ prevSegLen := oldSegs.LengthOfPrevSeg(currHfIdx) @@ -317,16 +327,14 @@ func (s *Raw) IncPath( /*@ ghost ubuf []byte @*/ ) (r error) { //@ XoverLeftSeg(tail, oldCurrInfIdx + 2, oldSegs) //@ XoverMidSeg(tail, oldCurrInfIdx - 1, oldSegs) //@ XoverRightSeg(tail, oldCurrInfIdx, oldCurrHfIdx, oldSegs) - //@ WidenCurrSeg(ubuf, offsetWithHops, currInfIdx, hfIdxSeg, segLen, MetaLen, MetaLen, len(ubuf)) - //@ WidenLeftSeg(ubuf, currInfIdx + 1, oldSegs, MetaLen, MetaLen, len(ubuf)) - //@ WidenMidSeg(ubuf, currInfIdx + 2, oldSegs, MetaLen, MetaLen, len(ubuf)) - //@ WidenRightSeg(ubuf, currInfIdx - 1, oldSegs, MetaLen, MetaLen, len(ubuf)) - //@ assert reveal s.absPkt(ubuf) == AbsXover(oldAbsPkt) + //@ WidenCurrSeg(newView, offsetWithHops, currInfIdx, hfIdxSeg, segLen, MetaLen, MetaLen, len(newView)) + //@ WidenLeftSeg(newView, currInfIdx + 1, oldSegs, MetaLen, MetaLen, len(newView)) + //@ WidenMidSeg(newView, currInfIdx + 2, oldSegs, MetaLen, MetaLen, len(newView)) + //@ WidenRightSeg(newView, currInfIdx - 1, oldSegs, MetaLen, MetaLen, len(newView)) + //@ assert newView[MetaLen:len(newView)] == tail + //@ assert reveal s.absPkt(newView) == AbsXover(oldAbsPkt) //@ } - //@ fold acc(sl.Bytes(tail, 0, len(tail)), R50) - //@ sl.Unslice_Bytes(ubuf, MetaLen, len(ubuf), HalfPerm) - //@ sl.CombineRange_Bytes(ubuf, 0, MetaLen, HalfPerm) //@ fold acc(s.Base.Mem(), R2) //@ fold acc(s.Mem(ubuf), HalfPerm) return err @@ -352,14 +360,17 @@ func (s *Raw) GetInfoField(idx int /*@, ghost ubuf []byte @*/) (ifield path.Info //@ fold acc(s.Base.Mem(), R12) infOffset := MetaLen + idx*path.InfoLen info /*@@@*/ := path.InfoField{} + //@ ghost v := sl.View(ubuf, 0, len(ubuf)) //@ sl.SplitRange_Bytes(ubuf, infOffset, infOffset+path.InfoLen, R20) if err := info.DecodeFromBytes(s.Raw[infOffset : infOffset+path.InfoLen]); err != nil { //@ Unreachable() return path.InfoField{}, err } - //@ sl.CombineRange_Bytes(ubuf, infOffset, infOffset+path.InfoLen, R21) - //@ path.BytesToAbsInfoFieldOffsetEq(ubuf, infOffset) - //@ sl.CombineRange_Bytes(ubuf, infOffset, infOffset+path.InfoLen, R21) + //@ ghost infoView := sl.View(s.Raw[infOffset:infOffset+path.InfoLen], 0, path.InfoLen) + //@ assert infoView[:path.InfoLen] == infoView + //@ assert infoView == v[infOffset:infOffset+path.InfoLen] + //@ sl.CombineRangeWithViews_Bytes(ubuf, infOffset, infOffset+path.InfoLen, R20, sl.View(ubuf, 0, infOffset), sl.View(ubuf[infOffset:infOffset+path.InfoLen], 0, (infOffset+path.InfoLen)-(infOffset)), sl.View(ubuf, infOffset+path.InfoLen, len(ubuf))) + //@ assert sl.View(ubuf, 0, len(ubuf)) == v //@ fold acc(s.Mem(ubuf), R11) //@ assert reveal s.CorrectlyDecodedInfWithIdx(ubuf, idx, info) return info, nil @@ -392,23 +403,25 @@ func (s *Raw) GetCurrentInfoField( /*@ ghost ubuf []byte @*/ ) (res path.InfoFie // @ requires sl.Bytes(ubuf, 0, len(ubuf)) // @ requires acc(s.Mem(ubuf), R20) // pres for IO: -// @ requires validPktMetaHdr(ubuf) -// @ requires s.GetBase(ubuf).EqAbsHeader(ubuf) +// @ requires validPktMetaHdr(sl.View(ubuf, 0, len(ubuf))) +// @ requires s.GetBase(ubuf).EqAbsHeader(sl.View(ubuf, 0, len(ubuf))) // @ ensures acc(s.Mem(ubuf), R20) // @ ensures sl.Bytes(ubuf, 0, len(ubuf)) // @ ensures r != nil ==> r.ErrorMem() // posts for IO: // @ ensures r == nil ==> -// @ validPktMetaHdr(ubuf) && s.GetBase(ubuf).EqAbsHeader(ubuf) +// @ validPktMetaHdr(sl.View(ubuf, 0, len(ubuf))) && +// @ s.GetBase(ubuf).EqAbsHeader(sl.View(ubuf, 0, len(ubuf))) // @ ensures r == nil && idx == int(old(s.GetCurrINF(ubuf))) ==> -// @ let oldPkt := old(s.absPkt(ubuf)) in +// @ let oldPkt := old(s.absPkt(sl.View(ubuf, 0, len(ubuf)))) in // @ let newPkt := oldPkt.UpdateInfoField(info.ToAbsInfoField()) in -// @ s.absPkt(ubuf) == newPkt +// @ s.absPkt(sl.View(ubuf, 0, len(ubuf))) == newPkt // @ decreases // @ #backend[exhaleMode(1)] func (s *Raw) SetInfoField(info path.InfoField, idx int /*@, ghost ubuf []byte @*/) (r error) { //@ share info - //@ reveal validPktMetaHdr(ubuf) + //@ ghost oldView := sl.View(ubuf, 0, len(ubuf)) + //@ reveal validPktMetaHdr(oldView) //@ unfold acc(s.Mem(ubuf), R50) //@ unfold acc(s.Base.Mem(), R50) //@ currInfIdx := int(s.PathMeta.CurrINF) @@ -429,38 +442,63 @@ func (s *Raw) SetInfoField(info path.InfoField, idx int /*@, ghost ubuf []byte @ } infOffset := MetaLen + idx*path.InfoLen - //@ SliceBytesIntoInfoFields(ubuf, s.NumINF, segLens, HalfPerm) - //@ SliceBytesIntoSegments(ubuf, segLens, R40) - - //@ ValidPktMetaHdrSublice(ubuf, MetaLen) - //@ oldInfo := path.BytesToAbsInfoField(ubuf[infOffset : infOffset+path.InfoLen], 0) + //@ oldInfo := path.BytesToAbsInfoField(oldView[infOffset : infOffset+path.InfoLen]) //@ newInfo := info.ToAbsInfoField() //@ hfIdxSeg := currHfIdx-prevSegLen - //@ hopfields := ubuf[offset:offset + segLen*path.HopLen] + //@ ghost hopfields := oldView[offset:offset + segLen*path.HopLen] //@ ghost if idx == currInfIdx { - //@ CurrSegEquality(ubuf, offset, currInfIdx, hfIdxSeg, segLen) - //@ LeftSegEquality(ubuf, currInfIdx+1, segLens) - //@ MidSegEquality(ubuf, currInfIdx+2, segLens) - //@ RightSegEquality(ubuf, currInfIdx-1, segLens) + //@ CurrSegEquality(oldView, offset, currInfIdx, hfIdxSeg, segLen) + //@ LeftSegEquality(oldView, currInfIdx+1, segLens) + //@ MidSegEquality(oldView, currInfIdx+2, segLens) + //@ RightSegEquality(oldView, currInfIdx-1, segLens) //@ } - //@ reveal s.absPkt(ubuf) - //@ sl.SplitRange_Bytes(ubuf[:hopfieldOffset], infOffset, infOffset+path.InfoLen, R40) - //@ sl.SplitRange_Bytes(ubuf, infOffset, infOffset+path.InfoLen, HalfPerm-R40) + //@ reveal s.absPkt(oldView) + //@ sl.SplitRange_Bytes(ubuf, infOffset, infOffset+path.InfoLen, writePerm) ret := info.SerializeTo(s.Raw[infOffset : infOffset+path.InfoLen]) - //@ sl.CombineRange_Bytes(ubuf[:hopfieldOffset], infOffset, infOffset+path.InfoLen, R40) - //@ sl.CombineRange_Bytes(ubuf, infOffset, infOffset+path.InfoLen, HalfPerm-R40) - //@ ValidPktMetaHdrSublice(ubuf, MetaLen) - //@ assert reveal validPktMetaHdr(ubuf) + //@ ghost newInfoView := sl.View(s.Raw[infOffset:infOffset+path.InfoLen], 0, path.InfoLen) + //@ assert newInfoView[:path.InfoLen] == newInfoView + //@ assert path.BytesToAbsInfoField(newInfoView) == newInfo + //@ sl.CombineRangeWithViews_Bytes(ubuf, infOffset, infOffset+path.InfoLen, writePerm, sl.View(ubuf, 0, infOffset), sl.View(ubuf[infOffset:infOffset+path.InfoLen], 0, (infOffset+path.InfoLen)-(infOffset)), sl.View(ubuf, infOffset+path.InfoLen, len(ubuf))) + //@ ghost newView := sl.View(ubuf, 0, len(ubuf)) + //@ assert newView[:infOffset] == oldView[:infOffset] + //@ assert newView[infOffset:infOffset+path.InfoLen] == newInfoView + //@ assert newView[infOffset+path.InfoLen:] == oldView[infOffset+path.InfoLen:] + //@ assert forall i int :: { newView[i] } 0 <= i && i < infOffset ==> + //@ newView[i] == oldView[i] + //@ assert forall i int :: { newView[i] } infOffset+path.InfoLen <= i && i < len(newView) ==> + //@ newView[i] == oldView[i] + //@ assert newView[0] == oldView[0] && newView[1] == oldView[1] && + //@ newView[2] == oldView[2] && newView[3] == oldView[3] + //@ assert RawBytesToMetaHdr(newView) == RawBytesToMetaHdr(oldView) + //@ assert RawBytesToBase(newView) == RawBytesToBase(oldView) + //@ assert reveal validPktMetaHdr(newView) //@ ghost if idx == currInfIdx { - //@ CurrSegEquality(ubuf, offset, currInfIdx, hfIdxSeg, segLen) + //@ assert newView[offset:offset + segLen*path.HopLen] == hopfields + //@ CurrSegEquality(newView, offset, currInfIdx, hfIdxSeg, segLen) //@ UpdateCurrSegInfo(hopfields, hfIdxSeg, segLen, oldInfo, newInfo) - //@ LeftSegEquality(ubuf, currInfIdx+1, segLens) - //@ MidSegEquality(ubuf, currInfIdx+2, segLens) - //@ RightSegEquality(ubuf, currInfIdx-1, segLens) - //@ reveal s.absPkt(ubuf) + //@ if (currInfIdx+1 == 1 && segLens.Seg2Len > 0) || + //@ (currInfIdx+1 == 2 && segLens.Seg2Len > 0 && segLens.Seg3Len > 0) { + //@ assert InfofieldByteSeq(newView, currInfIdx+1) == InfofieldByteSeq(oldView, currInfIdx+1) + //@ assert HopfieldsByteSeq(newView, currInfIdx+1, segLens) == HopfieldsByteSeq(oldView, currInfIdx+1, segLens) + //@ } + //@ if segLens.Seg2Len > 0 && segLens.Seg3Len > 0 && + //@ (currInfIdx+2 == 2 || currInfIdx+2 == 4) { + //@ assert InfofieldByteSeq(newView, currInfIdx+2) == InfofieldByteSeq(oldView, currInfIdx+2) + //@ assert HopfieldsByteSeq(newView, currInfIdx+2, segLens) == HopfieldsByteSeq(oldView, currInfIdx+2, segLens) + //@ } + //@ if (currInfIdx-1 == 0 && segLens.Seg2Len > 0) || + //@ (currInfIdx-1 == 1 && segLens.Seg2Len > 0 && segLens.Seg3Len > 0) { + //@ assert InfofieldByteSeq(newView, currInfIdx-1) == InfofieldByteSeq(oldView, currInfIdx-1) + //@ assert HopfieldsByteSeq(newView, currInfIdx-1, segLens) == HopfieldsByteSeq(oldView, currInfIdx-1, segLens) + //@ } + //@ LeftSegEquality(oldView, currInfIdx+1, segLens) + //@ MidSegEquality(oldView, currInfIdx+2, segLens) + //@ RightSegEquality(oldView, currInfIdx-1, segLens) + //@ LeftSegEquality(newView, currInfIdx+1, segLens) + //@ MidSegEquality(newView, currInfIdx+2, segLens) + //@ RightSegEquality(newView, currInfIdx-1, segLens) + //@ reveal s.absPkt(newView) //@ } - //@ CombineBytesFromSegments(ubuf, segLens, R40) - //@ CombineBytesFromInfoFields(ubuf, s.NumINF, segLens, HalfPerm) //@ fold acc(s.Base.Mem(), R50) //@ fold acc(s.Mem(ubuf), R50) return ret @@ -486,15 +524,17 @@ func (s *Raw) GetHopField(idx int /*@, ghost ubuf []byte @*/) (res path.HopField hopOffset := MetaLen + s.NumINF*path.InfoLen + idx*path.HopLen //@ fold acc(s.Base.Mem(), R12) hop /*@@@*/ := path.HopField{} + //@ ghost v := sl.View(ubuf, 0, len(ubuf)) //@ sl.SplitRange_Bytes(ubuf, hopOffset, hopOffset+path.HopLen, R20) if err := hop.DecodeFromBytes(s.Raw[hopOffset : hopOffset+path.HopLen]); err != nil { //@ Unreachable() return path.HopField{}, err } //@ unfold hop.Mem() - //@ sl.CombineRange_Bytes(ubuf, hopOffset, hopOffset+path.HopLen, R21) - //@ path.BytesToAbsHopFieldOffsetEq(ubuf, hopOffset) - //@ sl.CombineRange_Bytes(ubuf, hopOffset, hopOffset+path.HopLen, R21) + //@ ghost hopView := sl.View(s.Raw[hopOffset:hopOffset+path.HopLen], 0, path.HopLen) + //@ assert hopView == v[hopOffset:hopOffset+path.HopLen] + //@ sl.CombineRangeWithViews_Bytes(ubuf, hopOffset, hopOffset+path.HopLen, R20, sl.View(ubuf, 0, hopOffset), sl.View(ubuf[hopOffset:hopOffset+path.HopLen], 0, (hopOffset+path.HopLen)-(hopOffset)), sl.View(ubuf, hopOffset+path.HopLen, len(ubuf))) + //@ assert sl.View(ubuf, 0, len(ubuf)) == v //@ fold acc(s.Mem(ubuf), R11) //@ assert reveal s.CorrectlyDecodedHfWithIdx(ubuf, idx, hop) return hop, nil @@ -527,20 +567,20 @@ func (s *Raw) GetCurrentHopField( /*@ ghost ubuf []byte @*/ ) (res path.HopField // @ requires acc(s.Mem(ubuf), R20) // @ requires sl.Bytes(ubuf, 0, len(ubuf)) // pres for IO: -// @ requires validPktMetaHdr(ubuf) -// @ requires s.GetBase(ubuf).EqAbsHeader(ubuf) -// @ requires s.absPkt(ubuf).PathNotFullyTraversed() +// @ requires validPktMetaHdr(sl.View(ubuf, 0, len(ubuf))) +// @ requires s.GetBase(ubuf).EqAbsHeader(sl.View(ubuf, 0, len(ubuf))) +// @ requires s.absPkt(sl.View(ubuf, 0, len(ubuf))).PathNotFullyTraversed() // @ ensures acc(s.Mem(ubuf), R20) // @ ensures sl.Bytes(ubuf, 0, len(ubuf)) // @ ensures r != nil ==> r.ErrorMem() // posts for IO: // @ ensures r == nil ==> -// @ validPktMetaHdr(ubuf) && -// @ s.GetBase(ubuf).EqAbsHeader(ubuf) +// @ validPktMetaHdr(sl.View(ubuf, 0, len(ubuf))) && +// @ s.GetBase(ubuf).EqAbsHeader(sl.View(ubuf, 0, len(ubuf))) // @ ensures r == nil && idx == int(old(s.GetCurrHF(ubuf))) ==> -// @ let oldPkt := old(s.absPkt(ubuf)) in +// @ let oldPkt := old(s.absPkt(sl.View(ubuf, 0, len(ubuf)))) in // @ let newPkt := oldPkt.UpdateHopField(hop.Abs()) in -// @ s.absPkt(ubuf) == newPkt +// @ s.absPkt(sl.View(ubuf, 0, len(ubuf))) == newPkt // @ decreases // @ #backend[exhaleMode(1)] func (s *Raw) SetHopField(hop path.HopField, idx int /*@, ghost ubuf []byte @*/) (r error) { @@ -552,7 +592,8 @@ func (s *Raw) SetHopField(hop path.HopField, idx int /*@, ghost ubuf []byte @*/) // https://github.com/viperproject/gobra/issues/192 //@ assume 0 <= tmpHopField.ConsIngress && 0 <= tmpHopField.ConsEgress //@ fold acc(tmpHopField.Mem(), R9) - //@ reveal validPktMetaHdr(ubuf) + //@ ghost oldView := sl.View(ubuf, 0, len(ubuf)) + //@ reveal validPktMetaHdr(oldView) //@ unfold acc(s.Mem(ubuf), R50) //@ unfold acc(s.Base.Mem(), R50) //@ ghost currInfIdx := int(s.PathMeta.CurrINF) @@ -574,48 +615,66 @@ func (s *Raw) SetHopField(hop path.HopField, idx int /*@, ghost ubuf []byte @*/) } hopOffset := MetaLen + s.NumINF*path.InfoLen + idx*path.HopLen - //@ SliceBytesIntoSegments(ubuf, segLens, HalfPerm) - //@ SliceBytesIntoInfoFields(ubuf[:hopfieldOffset], s.NumINF, segLens, R40) - - //@ ValidPktMetaHdrSublice(ubuf, MetaLen) - //@ ghost inf := path.BytesToAbsInfoField(InfofieldByteSlice(ubuf, currInfIdx), 0) + //@ ghost inf := path.BytesToAbsInfoField(InfofieldByteSeq(oldView, currInfIdx)) //@ ghost hfIdxSeg := idx-prevSegLen - //@ ghost currHopfields := HopfieldsByteSlice(ubuf, currInfIdx, segLens) + //@ ghost currHopfields := HopfieldsByteSeq(oldView, currInfIdx, segLens) //@ ghost if idx == currHfIdx { - //@ CurrSegEquality(ubuf, offset, currInfIdx, hfIdxSeg, segLen) - //@ LeftSegEquality(ubuf, currInfIdx+1, segLens) - //@ MidSegEquality(ubuf, currInfIdx+2, segLens) - //@ RightSegEquality(ubuf, currInfIdx-1, segLens) - //@ reveal s.absPkt(ubuf) - //@ SplitHopfields(currHopfields, hfIdxSeg, segLen, R0) + //@ CurrSegEquality(oldView, offset, currInfIdx, hfIdxSeg, segLen) + //@ LeftSegEquality(oldView, currInfIdx+1, segLens) + //@ MidSegEquality(oldView, currInfIdx+2, segLens) + //@ RightSegEquality(oldView, currInfIdx-1, segLens) + //@ reveal s.absPkt(oldView) + //@ assert oldView[offset:offset+segLen*path.HopLen] == currHopfields //@ EstablishBytesStoreCurrSeg(currHopfields, hfIdxSeg, segLen, inf) - //@ SplitHopfields(currHopfields, hfIdxSeg, segLen, R0) - //@ } else { - //@ sl.SplitRange_Bytes(ubuf[offset:offset+segLen*path.HopLen], hfIdxSeg*path.HopLen, - //@ (hfIdxSeg+1)*path.HopLen, HalfPerm) //@ } - //@ sl.SplitRange_Bytes(ubuf, hopOffset, hopOffset+path.HopLen, HalfPerm) + //@ sl.SplitRange_Bytes(ubuf, hopOffset, hopOffset+path.HopLen, writePerm) ret := tmpHopField.SerializeTo(s.Raw[hopOffset : hopOffset+path.HopLen]) - //@ sl.CombineRange_Bytes(ubuf, hopOffset, hopOffset+path.HopLen, HalfPerm) - //@ ValidPktMetaHdrSublice(ubuf, MetaLen) - //@ assert reveal validPktMetaHdr(ubuf) + //@ ghost newHopView := sl.View(s.Raw[hopOffset:hopOffset+path.HopLen], 0, path.HopLen) + //@ assert path.BytesToIO_HF(newHopView) == tmpHopField.Abs() + //@ sl.CombineRangeWithViews_Bytes(ubuf, hopOffset, hopOffset+path.HopLen, writePerm, sl.View(ubuf, 0, hopOffset), sl.View(ubuf[hopOffset:hopOffset+path.HopLen], 0, (hopOffset+path.HopLen)-(hopOffset)), sl.View(ubuf, hopOffset+path.HopLen, len(ubuf))) + //@ ghost newView := sl.View(ubuf, 0, len(ubuf)) + //@ assert newView[:hopOffset] == oldView[:hopOffset] + //@ assert newView[hopOffset:hopOffset+path.HopLen] == newHopView + //@ assert newView[hopOffset+path.HopLen:] == oldView[hopOffset+path.HopLen:] + //@ assert forall i int :: { newView[i] } 0 <= i && i < hopOffset ==> + //@ newView[i] == oldView[i] + //@ assert forall i int :: { newView[i] } hopOffset+path.HopLen <= i && i < len(newView) ==> + //@ newView[i] == oldView[i] + //@ assert newView[0] == oldView[0] && newView[1] == oldView[1] && + //@ newView[2] == oldView[2] && newView[3] == oldView[3] + //@ assert RawBytesToMetaHdr(newView) == RawBytesToMetaHdr(oldView) + //@ assert RawBytesToBase(newView) == RawBytesToBase(oldView) + //@ assert reveal validPktMetaHdr(newView) //@ ghost if idx == currHfIdx { - //@ CombineHopfields(currHopfields, hfIdxSeg, segLen, R0) - //@ EstablishBytesStoreCurrSeg(currHopfields, hfIdxSeg, segLen, inf) - //@ CombineHopfields(currHopfields, hfIdxSeg, segLen, R0) - //@ CurrSegEquality(ubuf, offset, currInfIdx, hfIdxSeg, segLen) - //@ LeftSegEquality(ubuf, currInfIdx+1, segLens) - //@ MidSegEquality(ubuf, currInfIdx+2, segLens) - //@ RightSegEquality(ubuf, currInfIdx-1, segLens) - //@ reveal s.absPkt(ubuf) - //@ assert s.absPkt(ubuf).CurrSeg.Future == - //@ seq[io.HF]{tmpHopField.Abs()} ++ old(s.absPkt(ubuf).CurrSeg.Future[1:]) - //@ } else { - //@ sl.CombineRange_Bytes(ubuf[offset:offset+segLen*path.HopLen], hfIdxSeg*path.HopLen, - //@ (hfIdxSeg+1)*path.HopLen, HalfPerm) + //@ ghost newHopfields := HopfieldsByteSeq(newView, currInfIdx, segLens) + //@ assert InfofieldByteSeq(newView, currInfIdx) == InfofieldByteSeq(oldView, currInfIdx) + //@ assert newHopfields[:hfIdxSeg*path.HopLen] == currHopfields[:hfIdxSeg*path.HopLen] + //@ assert newHopfields[hfIdxSeg*path.HopLen:(hfIdxSeg+1)*path.HopLen] == newHopView + //@ assert newHopfields[(hfIdxSeg+1)*path.HopLen:] == currHopfields[(hfIdxSeg+1)*path.HopLen:] + //@ CurrSegEquality(newView, offset, currInfIdx, hfIdxSeg, segLen) + //@ EstablishBytesStoreCurrSeg(newHopfields, hfIdxSeg, segLen, inf) + //@ if (currInfIdx+1 == 1 && segLens.Seg2Len > 0) || + //@ (currInfIdx+1 == 2 && segLens.Seg2Len > 0 && segLens.Seg3Len > 0) { + //@ assert InfofieldByteSeq(newView, currInfIdx+1) == InfofieldByteSeq(oldView, currInfIdx+1) + //@ assert HopfieldsByteSeq(newView, currInfIdx+1, segLens) == HopfieldsByteSeq(oldView, currInfIdx+1, segLens) + //@ } + //@ if segLens.Seg2Len > 0 && segLens.Seg3Len > 0 && + //@ (currInfIdx+2 == 2 || currInfIdx+2 == 4) { + //@ assert InfofieldByteSeq(newView, currInfIdx+2) == InfofieldByteSeq(oldView, currInfIdx+2) + //@ assert HopfieldsByteSeq(newView, currInfIdx+2, segLens) == HopfieldsByteSeq(oldView, currInfIdx+2, segLens) + //@ } + //@ if (currInfIdx-1 == 0 && segLens.Seg2Len > 0) || + //@ (currInfIdx-1 == 1 && segLens.Seg2Len > 0 && segLens.Seg3Len > 0) { + //@ assert InfofieldByteSeq(newView, currInfIdx-1) == InfofieldByteSeq(oldView, currInfIdx-1) + //@ assert HopfieldsByteSeq(newView, currInfIdx-1, segLens) == HopfieldsByteSeq(oldView, currInfIdx-1, segLens) + //@ } + //@ LeftSegEquality(newView, currInfIdx+1, segLens) + //@ MidSegEquality(newView, currInfIdx+2, segLens) + //@ RightSegEquality(newView, currInfIdx-1, segLens) + //@ reveal s.absPkt(newView) + //@ assert s.absPkt(newView).CurrSeg.Future == + //@ seq[io.HF]{tmpHopField.Abs()} ++ old(s.absPkt(sl.View(ubuf, 0, len(ubuf))).CurrSeg.Future[1:]) //@ } - //@ CombineBytesFromInfoFields(ubuf[:hopfieldOffset], s.NumINF, segLens, R40) - //@ CombineBytesFromSegments(ubuf, segLens, HalfPerm) //@ fold acc(s.Base.Mem(), R50) //@ fold acc(s.Mem(ubuf), R50) return ret diff --git a/pkg/slayers/path/scion/raw_spec.gobra b/pkg/slayers/path/scion/raw_spec.gobra index 218a6a38e..a752e3fd4 100644 --- a/pkg/slayers/path/scion/raw_spec.gobra +++ b/pkg/slayers/path/scion/raw_spec.gobra @@ -47,7 +47,7 @@ requires sl.Bytes(buf, 0, len(buf)) decreases pure func (s *Raw) IsValidResultOfDecoding(buf []byte) bool { return let base := s.GetBase(buf) in - base.EqAbsHeader(buf) && + base.EqAbsHeader(sl.View(buf, 0, len(buf))) && base.WeaklyValid() } @@ -216,20 +216,32 @@ pure func PktLen(segs io.SegLens, headerOffset int) int { path.HopLen * segs.TotalHops() } +// InfofieldBytes returns the bytes of the infofield with index currInfIdx +// in the view of the packet raw bytes. +ghost +requires 0 <= currInfIdx && 0 <= headerOffset +requires path.InfoFieldOffset(currInfIdx, headerOffset) + path.InfoLen <= len(raw) +ensures len(res) == path.InfoLen +decreases +pure func InfofieldBytes(raw seq[byte], currInfIdx int, headerOffset int) (res seq[byte]) { + return let infOffset := path.InfoFieldOffset(currInfIdx, headerOffset) in + raw[infOffset:infOffset + path.InfoLen] +} + ghost requires 0 <= offset requires 0 <= currHfIdx && currHfIdx <= segLen requires offset + path.HopLen * segLen <= len(raw) -requires sl.Bytes(raw, 0, len(raw)) ensures len(res) == segLen - currHfIdx decreases segLen - currHfIdx pure func hopFields( - raw []byte, + raw seq[byte], offset int, currHfIdx int, segLen int) (res seq[io.HF]) { return currHfIdx == segLen ? seq[io.HF]{} : - let hf := path.BytesToIO_HF(raw, 0, offset + path.HopLen * currHfIdx, len(raw)) in + let start := offset + path.HopLen * currHfIdx in + let hf := path.BytesToIO_HF(raw[start:start + path.HopLen]) in seq[io.HF]{hf} ++ hopFields(raw, offset, currHfIdx + 1, segLen) } @@ -252,7 +264,6 @@ pure func segHistory(hopfields seq[io.HF]) (res seq[io.AHI]) { } ghost -requires sl.Bytes(raw, 0, len(raw)) requires 0 <= offset requires 0 < segLen requires 0 <= currHfIdx && currHfIdx <= segLen @@ -261,7 +272,7 @@ ensures len(res.Future) == segLen - currHfIdx ensures len(res.History) == currHfIdx ensures len(res.Past) == currHfIdx decreases -pure func segment(raw []byte, +pure func segment(raw seq[byte], offset int, currHfIdx int, ainfo io.Ainfo, @@ -283,7 +294,6 @@ pure func segment(raw []byte, ghost opaque -requires sl.Bytes(raw, 0, len(raw)) requires 0 <= headerOffset requires path.InfoFieldOffset(currInfIdx, headerOffset) + path.InfoLen <= offset requires 0 < segLen @@ -294,29 +304,29 @@ ensures len(res.Future) == segLen - currHfIdx ensures len(res.History) == currHfIdx ensures len(res.Past) == currHfIdx decreases -pure func CurrSeg(raw []byte, +pure func CurrSeg(raw seq[byte], offset int, currInfIdx int, currHfIdx int, segLen int, headerOffset int) (res io.Seg) { - return let ainfo := path.Timestamp(raw, currInfIdx, headerOffset) in - let consDir := path.ConsDir(raw, currInfIdx, headerOffset) in - let peer := path.Peer(raw, currInfIdx, headerOffset) in - let uinfo := path.AbsUinfo(raw, currInfIdx, headerOffset) in + return let infoBytes := InfofieldBytes(raw, currInfIdx, headerOffset) in + let ainfo := path.Timestamp(infoBytes) in + let consDir := path.ConsDir(infoBytes) in + let peer := path.Peer(infoBytes) in + let uinfo := path.AbsUinfo(infoBytes) in segment(raw, offset, currHfIdx, ainfo, uinfo, consDir, peer, segLen) } ghost opaque -requires sl.Bytes(raw, 0, len(raw)) requires 0 <= headerOffset requires segs.Valid() requires PktLen(segs, headerOffset) <= len(raw) requires 1 <= currInfIdx && currInfIdx < 4 decreases pure func LeftSeg( - raw []byte, + raw seq[byte], currInfIdx int, segs io.SegLens, headerOffset int) option[io.Seg] { @@ -330,14 +340,13 @@ pure func LeftSeg( ghost opaque -requires sl.Bytes(raw, 0, len(raw)) requires 0 <= headerOffset requires segs.Valid() requires PktLen(segs, headerOffset) <= len(raw) requires -1 <= currInfIdx && currInfIdx < 2 decreases pure func RightSeg( - raw []byte, + raw seq[byte], currInfIdx int, segs io.SegLens, headerOffset int) option[io.Seg] { @@ -351,14 +360,13 @@ pure func RightSeg( ghost opaque -requires sl.Bytes(raw, 0, len(raw)) requires 0 <= headerOffset requires segs.Valid() requires PktLen(segs, headerOffset) <= len(raw) requires 2 <= currInfIdx && currInfIdx < 5 decreases pure func MidSeg( - raw []byte, + raw seq[byte], currInfIdx int, segs io.SegLens, headerOffset int) option[io.Seg] { @@ -372,11 +380,9 @@ pure func MidSeg( ghost opaque -requires sl.Bytes(raw, 0, len(raw)) requires validPktMetaHdr(raw) decreases -// TODO: rename this to View() -pure func (s *Raw) absPkt(raw []byte) (res io.Pkt) { +pure func (s *Raw) absPkt(raw seq[byte]) (res io.Pkt) { return let _ := reveal validPktMetaHdr(raw) in let metaHdr := RawBytesToMetaHdr(raw) in let currInfIdx := int(metaHdr.CurrINF) in @@ -399,19 +405,16 @@ pure func (s *Raw) absPkt(raw []byte) (res io.Pkt) { ghost requires MetaLen <= len(raw) -requires sl.Bytes(raw, 0, len(raw)) decreases -pure func RawBytesToMetaHdr(raw []byte) MetaHdr { - return unfolding sl.Bytes(raw, 0, len(raw)) in - let hdr := binary.BigEndian.Uint32(raw[:MetaLen]) in +pure func RawBytesToMetaHdr(raw seq[byte]) MetaHdr { + return let hdr := binary.BigEndian.Uint32Spec(raw[0], raw[1], raw[2], raw[3]) in DecodedFrom(hdr) } ghost requires MetaLen <= len(raw) -requires sl.Bytes(raw, 0, len(raw)) decreases -pure func RawBytesToBase(raw []byte) Base { +pure func RawBytesToBase(raw seq[byte]) Base { return let metaHdr := RawBytesToMetaHdr(raw) in let seg1 := int(metaHdr.SegLen[0]) in let seg2 := int(metaHdr.SegLen[1]) in @@ -422,9 +425,8 @@ pure func RawBytesToBase(raw []byte) Base { ghost opaque -requires sl.Bytes(raw, 0, len(raw)) decreases -pure func validPktMetaHdr(raw []byte) bool { +pure func validPktMetaHdr(raw seq[byte]) bool { return MetaLen <= len(raw) && let metaHdr := RawBytesToMetaHdr(raw) in let seg1 := int(metaHdr.SegLen[0]) in @@ -437,39 +439,36 @@ pure func validPktMetaHdr(raw []byte) bool { PktLen(segs, MetaLen) <= len(raw) } +// The meta header of a packet only depends on its first MetaLen bytes. ghost -requires MetaLen <= idx && idx <= len(raw) -preserves acc(sl.Bytes(raw, 0, len(raw)), R56) -preserves acc(sl.Bytes(raw[:idx], 0, idx), R56) -ensures RawBytesToMetaHdr(raw) == RawBytesToMetaHdr(raw[:idx]) -ensures RawBytesToBase(raw) == RawBytesToBase(raw[:idx]) +requires MetaLen <= idx && idx <= len(raw) +ensures RawBytesToMetaHdr(raw) == RawBytesToMetaHdr(raw[:idx]) +ensures RawBytesToBase(raw) == RawBytesToBase(raw[:idx]) decreases -func ValidPktMetaHdrSublice(raw []byte, idx int) { - reveal validPktMetaHdr(raw) - reveal validPktMetaHdr(raw[:idx]) - unfold acc(sl.Bytes(raw, 0, len(raw)), R56) - unfold acc(sl.Bytes(raw[:idx], 0, idx), R56) - assert forall i int :: { &raw[:MetaLen][i] } 0 <= i && i < MetaLen ==> - &raw[:MetaLen][i] == &raw[:idx][:MetaLen][i] - fold acc(sl.Bytes(raw, 0, len(raw)), R56) - fold acc(sl.Bytes(raw[:idx], 0, idx), R56) +func ValidPktMetaHdrSublice(raw seq[byte], idx int) { + assert raw[:idx][0] == raw[0] && + raw[:idx][1] == raw[1] && + raw[:idx][2] == raw[2] && + raw[:idx][3] == raw[3] } ghost requires acc(s.Mem(ub), R54) requires acc(sl.Bytes(ub, 0, len(ub)), R55) requires s.GetBase(ub).Valid() -requires s.GetBase(ub).EqAbsHeader(ub) +requires s.GetBase(ub).EqAbsHeader(sl.View(ub, 0, len(ub))) ensures acc(sl.Bytes(ub, 0, len(ub)), R55) ensures acc(s.Mem(ub), R54) -ensures validPktMetaHdr(ub) -ensures s.GetBase(ub).EqAbsHeader(ub) +ensures validPktMetaHdr(sl.View(ub, 0, len(ub))) +ensures s.GetBase(ub).EqAbsHeader(sl.View(ub, 0, len(ub))) decreases func (s *Raw) EstablishValidPktMetaHdr(ghost ub []byte) { + v := sl.View(ub, 0, len(ub)) + assert len(v) == len(ub) unfold acc(s.Mem(ub), R55) unfold acc(s.Base.Mem(), R56) assert MetaLen <= len(ub) - assert s.Base.GetBase() == RawBytesToBase(ub) + assert s.Base.GetBase() == RawBytesToBase(v) seg1 := int(s.Base.PathMeta.SegLen[0]) seg2 := int(s.Base.PathMeta.SegLen[1]) seg3 := int(s.Base.PathMeta.SegLen[2]) @@ -477,7 +476,7 @@ func (s *Raw) EstablishValidPktMetaHdr(ghost ub []byte) { assert 0 < seg1 assert s.GetBase(ub).NumsCompatibleWithSegLen() assert PktLen(segs, MetaLen) <= len(ub) - assert reveal validPktMetaHdr(ub) + assert reveal validPktMetaHdr(v) fold acc(s.Base.Mem(), R56) fold acc(s.Mem(ub), R55) } @@ -543,7 +542,8 @@ pure func (s *Raw) CorrectlyDecodedInfWithIdx(ub []byte, idx int, info path.Info let infOffset := MetaLen + idx*path.InfoLen in infOffset + path.InfoLen <= len(ub) && info.ToAbsInfoField() == - reveal path.BytesToAbsInfoField(ub, infOffset) + reveal path.BytesToAbsInfoField( + sl.View(ub, 0, len(ub))[infOffset:infOffset + path.InfoLen]) } ghost @@ -558,7 +558,8 @@ pure func (s *Raw) CorrectlyDecodedInf(ub []byte, info path.InfoField) bool { let infOffset := MetaLen + int(s.Base.PathMeta.CurrINF) * path.InfoLen in infOffset + path.InfoLen <= len(ub) && info.ToAbsInfoField() == - reveal path.BytesToAbsInfoField(ub, infOffset) + reveal path.BytesToAbsInfoField( + sl.View(ub, 0, len(ub))[infOffset:infOffset + path.InfoLen]) } ghost @@ -572,7 +573,8 @@ pure func (s *Raw) CorrectlyDecodedHfWithIdx(ub []byte, idx int, hop path.HopFie unfolding s.Base.Mem() in let hopOffset := MetaLen + int(s.NumINF) * path.InfoLen + idx * path.HopLen in hopOffset + path.HopLen <= len(ub) && - hop.Abs() == path.BytesToIO_HF(ub, 0, hopOffset, len(ub)) + hop.Abs() == path.BytesToIO_HF( + sl.View(ub, 0, len(ub))[hopOffset:hopOffset + path.HopLen]) } ghost @@ -587,20 +589,22 @@ pure func (s *Raw) CorrectlyDecodedHf(ub []byte, hop path.HopField) bool { let hopOffset := MetaLen + int(s.NumINF) * path.InfoLen + int(s.Base.PathMeta.CurrHF) * path.HopLen in hopOffset + path.HopLen <= len(ub) && - hop.Abs() == path.BytesToIO_HF(ub, 0, hopOffset, len(ub)) + hop.Abs() == path.BytesToIO_HF( + sl.View(ub, 0, len(ub))[hopOffset:hopOffset + path.HopLen]) } ghost preserves acc(s.Mem(ubuf), R55) preserves s.IsLastHopSpec(ubuf) preserves acc(sl.Bytes(ubuf, 0, len(ubuf)), R56) -preserves validPktMetaHdr(ubuf) -preserves s.GetBase(ubuf).EqAbsHeader(ubuf) -ensures len(s.absPkt(ubuf).CurrSeg.Future) == 1 +preserves validPktMetaHdr(sl.View(ubuf, 0, len(ubuf))) +preserves s.GetBase(ubuf).EqAbsHeader(sl.View(ubuf, 0, len(ubuf))) +ensures len(s.absPkt(sl.View(ubuf, 0, len(ubuf))).CurrSeg.Future) == 1 decreases func (s *Raw) LastHopLemma(ubuf []byte) { - reveal validPktMetaHdr(ubuf) - metaHdr := RawBytesToMetaHdr(ubuf) + v := sl.View(ubuf, 0, len(ubuf)) + reveal validPktMetaHdr(v) + metaHdr := RawBytesToMetaHdr(v) currInfIdx := int(metaHdr.CurrINF) currHfIdx := int(metaHdr.CurrHF) seg1Len := int(metaHdr.SegLen[0]) @@ -611,8 +615,8 @@ func (s *Raw) LastHopLemma(ubuf []byte) { prevSegLen := segs.LengthOfPrevSeg(currHfIdx) numINF := segs.NumInfoFields() offset := HopFieldOffset(numINF, prevSegLen, MetaLen) - pkt := reveal s.absPkt(ubuf) - assert pkt.CurrSeg == reveal CurrSeg(ubuf, offset, currInfIdx, currHfIdx - prevSegLen, segLen, MetaLen) + pkt := reveal s.absPkt(v) + assert pkt.CurrSeg == reveal CurrSeg(v, offset, currInfIdx, currHfIdx - prevSegLen, segLen, MetaLen) assert len(pkt.CurrSeg.Future) == 1 } @@ -620,16 +624,17 @@ ghost preserves acc(s.Mem(ubuf), R55) preserves s.GetBase(ubuf).IsXoverSpec() preserves acc(sl.Bytes(ubuf, 0, len(ubuf)), R56) -preserves validPktMetaHdr(ubuf) -preserves s.GetBase(ubuf).EqAbsHeader(ubuf) -ensures s.absPkt(ubuf).LeftSeg != none[io.Seg] -ensures len(s.absPkt(ubuf).CurrSeg.Future) == 1 -ensures len(get(s.absPkt(ubuf).LeftSeg).Future) > 0 -ensures len(get(s.absPkt(ubuf).LeftSeg).History) == 0 +preserves validPktMetaHdr(sl.View(ubuf, 0, len(ubuf))) +preserves s.GetBase(ubuf).EqAbsHeader(sl.View(ubuf, 0, len(ubuf))) +ensures s.absPkt(sl.View(ubuf, 0, len(ubuf))).LeftSeg != none[io.Seg] +ensures len(s.absPkt(sl.View(ubuf, 0, len(ubuf))).CurrSeg.Future) == 1 +ensures len(get(s.absPkt(sl.View(ubuf, 0, len(ubuf))).LeftSeg).Future) > 0 +ensures len(get(s.absPkt(sl.View(ubuf, 0, len(ubuf))).LeftSeg).History) == 0 decreases func (s *Raw) XoverLemma(ubuf []byte) { - reveal validPktMetaHdr(ubuf) - metaHdr := RawBytesToMetaHdr(ubuf) + v := sl.View(ubuf, 0, len(ubuf)) + reveal validPktMetaHdr(v) + metaHdr := RawBytesToMetaHdr(v) currInfIdx := int(metaHdr.CurrINF) currHfIdx := int(metaHdr.CurrHF) seg1Len := int(metaHdr.SegLen[0]) @@ -640,12 +645,12 @@ func (s *Raw) XoverLemma(ubuf []byte) { prevSegLen := segs.LengthOfPrevSeg(currHfIdx) numINF := segs.NumInfoFields() offset := HopFieldOffset(numINF, prevSegLen, MetaLen) - pkt := reveal s.absPkt(ubuf) - assert pkt.CurrSeg == reveal CurrSeg(ubuf, offset, currInfIdx, currHfIdx - prevSegLen, segLen, MetaLen) - assert pkt.LeftSeg == reveal LeftSeg(ubuf, currInfIdx + 1, segs, MetaLen) + pkt := reveal s.absPkt(v) + assert pkt.CurrSeg == reveal CurrSeg(v, offset, currInfIdx, currHfIdx - prevSegLen, segLen, MetaLen) + assert pkt.LeftSeg == reveal LeftSeg(v, currInfIdx + 1, segs, MetaLen) assert len(pkt.CurrSeg.Future) == 1 assert pkt.LeftSeg != none[io.Seg] - assert len(get(s.absPkt(ubuf).LeftSeg).History) == 0 + assert len(get(s.absPkt(v).LeftSeg).History) == 0 assert len(get(pkt.LeftSeg).Future) > 0 } @@ -672,19 +677,20 @@ pure func (s *Raw) EqAbsInfoField(pkt io.Pkt, info io.AbsInfoField) bool { ghost preserves acc(s.Mem(ubuf), R53) preserves acc(sl.Bytes(ubuf, 0, len(ubuf)), R53) -preserves validPktMetaHdr(ubuf) -preserves s.GetBase(ubuf).EqAbsHeader(ubuf) -preserves s.absPkt(ubuf).PathNotFullyTraversed() +preserves validPktMetaHdr(sl.View(ubuf, 0, len(ubuf))) +preserves s.GetBase(ubuf).EqAbsHeader(sl.View(ubuf, 0, len(ubuf))) +preserves s.absPkt(sl.View(ubuf, 0, len(ubuf))).PathNotFullyTraversed() preserves s.GetBase(ubuf).ValidCurrInfSpec() preserves s.GetBase(ubuf).ValidCurrHfSpec() preserves s.CorrectlyDecodedInf(ubuf, info) preserves s.CorrectlyDecodedHf(ubuf, hop) -ensures s.EqAbsInfoField(s.absPkt(ubuf), info.ToAbsInfoField()) -ensures s.EqAbsHopField(s.absPkt(ubuf), hop.Abs()) +ensures s.EqAbsInfoField(s.absPkt(sl.View(ubuf, 0, len(ubuf))), info.ToAbsInfoField()) +ensures s.EqAbsHopField(s.absPkt(sl.View(ubuf, 0, len(ubuf))), hop.Abs()) decreases func (s *Raw) DecodingLemma(ubuf []byte, info path.InfoField, hop path.HopField) { - assert reveal validPktMetaHdr(ubuf) - metaHdr := RawBytesToMetaHdr(ubuf) + v := sl.View(ubuf, 0, len(ubuf)) + assert reveal validPktMetaHdr(v) + metaHdr := RawBytesToMetaHdr(v) currInfIdx := int(metaHdr.CurrINF) currHfIdx := int(metaHdr.CurrHF) seg1Len := int(metaHdr.SegLen[0]) @@ -699,23 +705,22 @@ func (s *Raw) DecodingLemma(ubuf []byte, info path.InfoField, hop path.HopField) assert reveal s.CorrectlyDecodedInf(ubuf, info) assert reveal s.CorrectlyDecodedHf(ubuf, hop) - currSeg := reveal CurrSeg(ubuf, offset, currInfIdx, hfIdxSeg, segLen, MetaLen) - HopsFromPrefixOfRawMatchPrefixOfHops(ubuf, offset, 0, segLen, hfIdxSeg) + currSeg := reveal CurrSeg(v, offset, currInfIdx, hfIdxSeg, segLen, MetaLen) + HopsFromPrefixOfRawMatchPrefixOfHops(v, offset, 0, segLen, hfIdxSeg) - pktView := reveal s.absPkt(ubuf) + pktView := reveal s.absPkt(v) infoView := info.ToAbsInfoField() // assertions for proving s.EqAbsInfoField(pktView, infoView) { + infOffset := MetaLen + currInfIdx * path.InfoLen + infoBytes := InfofieldBytes(v, currInfIdx, MetaLen) // equality of Peer assert pktView.CurrSeg.Peer == infoView.Peer // equality of AInfo - assert currSeg.AInfo == path.Timestamp(ubuf, currInfIdx, MetaLen) - infOffset := MetaLen + currInfIdx * path.InfoLen - sl.AssertSliceOverlap(ubuf, infOffset+4, infOffset+8) + assert currSeg.AInfo == path.Timestamp(infoBytes) assert pktView.CurrSeg.AInfo == infoView.AInfo // equality of UInfo - sl.AssertSliceOverlap(ubuf, infOffset+2, infOffset+4) assert pktView.CurrSeg.UInfo == infoView.UInfo } @@ -724,45 +729,42 @@ func (s *Raw) DecodingLemma(ubuf []byte, info path.InfoField, hop path.HopField) } ghost -requires path.InfoFieldOffset(currInfIdx, 0) + path.InfoLen <= offset -requires 0 < segLen -requires offset + path.HopLen * segLen <= len(raw) -requires 0 <= currHfIdx && currHfIdx < segLen -requires 0 <= currInfIdx && currInfIdx < 3 -preserves acc(sl.Bytes(raw, 0, len(raw)), R56) -ensures len(CurrSeg(raw, offset, currInfIdx, currHfIdx, segLen, 0).Future) > 0 +requires path.InfoFieldOffset(currInfIdx, 0) + path.InfoLen <= offset +requires 0 < segLen +requires offset + path.HopLen * segLen <= len(raw) +requires 0 <= currHfIdx && currHfIdx < segLen +requires 0 <= currInfIdx && currInfIdx < 3 +ensures len(CurrSeg(raw, offset, currInfIdx, currHfIdx, segLen, 0).Future) > 0 decreases -func LenCurrSeg(raw []byte, offset int, currInfIdx int, currHfIdx int, segLen int) { +func LenCurrSeg(raw seq[byte], offset int, currInfIdx int, currHfIdx int, segLen int) { reveal CurrSeg(raw, offset, currInfIdx, currHfIdx, segLen, 0) } ghost -requires segs.Valid() -requires 0 < segs.Seg2Len -requires PktLen(segs, 0) <= len(raw) -requires 0 <= currInfIdx && currInfIdx < 2 -requires 1 <= currInfIdx ==> 0 < segs.Seg3Len -preserves acc(sl.Bytes(raw, 0, len(raw)), R56) -ensures LeftSeg(raw, currInfIdx + 1, segs, 0) != none[io.Seg] -ensures RightSeg(raw, currInfIdx, segs, 0) != none[io.Seg] -decreases -func XoverSegNotNone(raw []byte, currInfIdx int, segs io.SegLens) { +requires segs.Valid() +requires 0 < segs.Seg2Len +requires PktLen(segs, 0) <= len(raw) +requires 0 <= currInfIdx && currInfIdx < 2 +requires 1 <= currInfIdx ==> 0 < segs.Seg3Len +ensures LeftSeg(raw, currInfIdx + 1, segs, 0) != none[io.Seg] +ensures RightSeg(raw, currInfIdx, segs, 0) != none[io.Seg] +decreases +func XoverSegNotNone(raw seq[byte], currInfIdx int, segs io.SegLens) { reveal LeftSeg(raw, currInfIdx + 1, segs, 0) reveal RightSeg(raw, currInfIdx, segs, 0) } ghost -requires path.InfoFieldOffset(currInfIdx, 0) + path.InfoLen <= offset -requires 0 < segLen -requires offset + path.HopLen * segLen <= len(raw) -requires 0 <= currHfIdx && currHfIdx < segLen -requires 0 <= currInfIdx && currInfIdx < 3 -preserves acc(sl.Bytes(raw, 0, len(raw)), R56) -preserves len(CurrSeg(raw, offset, currInfIdx, currHfIdx, segLen, 0).Future) > 0 -ensures CurrSeg(raw, offset, currInfIdx, currHfIdx + 1, segLen, 0) == +requires path.InfoFieldOffset(currInfIdx, 0) + path.InfoLen <= offset +requires 0 < segLen +requires offset + path.HopLen * segLen <= len(raw) +requires 0 <= currHfIdx && currHfIdx < segLen +requires 0 <= currInfIdx && currInfIdx < 3 +requires len(CurrSeg(raw, offset, currInfIdx, currHfIdx, segLen, 0).Future) > 0 +ensures CurrSeg(raw, offset, currInfIdx, currHfIdx + 1, segLen, 0) == absIncPathSeg(CurrSeg(raw, offset, currInfIdx, currHfIdx, segLen, 0)) decreases -func IncCurrSeg(raw []byte, offset int, currInfIdx int, currHfIdx int, segLen int) { +func IncCurrSeg(raw seq[byte], offset int, currInfIdx int, currHfIdx int, segLen int) { currseg := reveal CurrSeg(raw, offset, currInfIdx, currHfIdx, segLen, 0) incseg := reveal CurrSeg(raw, offset, currInfIdx, currHfIdx + 1, segLen, 0) hf := hopFields(raw, offset, 0, segLen) @@ -779,15 +781,14 @@ func IncCurrSeg(raw []byte, offset int, currInfIdx int, currHfIdx int, segLen in } ghost -requires segs.Valid() -requires 0 < segs.Seg2Len -requires PktLen(segs, 0) <= len(raw) -requires 1 <= currInfIdx && currInfIdx < 3 -requires 1 == currInfIdx ==> currHfIdx + 1 == segs.Seg1Len -requires 2 == currInfIdx ==> 0 < segs.Seg3Len && currHfIdx + 1 == segs.Seg1Len + segs.Seg2Len -requires PktLen(segs, 0) <= len(raw) -preserves acc(sl.Bytes(raw, 0, len(raw)), R56) -preserves LeftSeg(raw, currInfIdx, segs, 0) != none[io.Seg] +requires segs.Valid() +requires 0 < segs.Seg2Len +requires PktLen(segs, 0) <= len(raw) +requires 1 <= currInfIdx && currInfIdx < 3 +requires 1 == currInfIdx ==> currHfIdx + 1 == segs.Seg1Len +requires 2 == currInfIdx ==> 0 < segs.Seg3Len && currHfIdx + 1 == segs.Seg1Len + segs.Seg2Len +requires LeftSeg(raw, currInfIdx, segs, 0) != none[io.Seg] +ensures LeftSeg(raw, currInfIdx, segs, 0) != none[io.Seg] ensures let prevSegLen := segs.LengthOfPrevSeg(currHfIdx + 1) in let segLen := segs.LengthOfCurrSeg(currHfIdx + 1) in @@ -796,7 +797,7 @@ ensures CurrSeg(raw, offset, currInfIdx, currHfIdx - prevSegLen + 1, segLen, 0) == get(LeftSeg(raw, currInfIdx, segs, 0)) decreases -func XoverCurrSeg(raw []byte, currInfIdx int, currHfIdx int, segs io.SegLens) { +func XoverCurrSeg(raw seq[byte], currInfIdx int, currHfIdx int, segs io.SegLens) { prevSegLen := segs.LengthOfPrevSeg(currHfIdx + 1) segLen := segs.LengthOfCurrSeg(currHfIdx + 1) numInf := segs.NumInfoFields() @@ -807,45 +808,42 @@ func XoverCurrSeg(raw []byte, currInfIdx int, currHfIdx int, segs io.SegLens) { } ghost -requires segs.Valid() -requires PktLen(segs, 0) <= len(raw) -requires 2 <= currInfIdx && currInfIdx < 4 -preserves acc(sl.Bytes(raw, 0, len(raw)), R56) -ensures LeftSeg(raw, currInfIdx, segs, 0) == +requires segs.Valid() +requires PktLen(segs, 0) <= len(raw) +requires 2 <= currInfIdx && currInfIdx < 4 +ensures LeftSeg(raw, currInfIdx, segs, 0) == MidSeg(raw, currInfIdx, segs, 0) decreases -func XoverLeftSeg(raw []byte, currInfIdx int, segs io.SegLens) { +func XoverLeftSeg(raw seq[byte], currInfIdx int, segs io.SegLens) { leftseg := reveal LeftSeg(raw, currInfIdx, segs, 0) midseg := reveal MidSeg(raw, currInfIdx, segs, 0) assert leftseg == midseg } ghost -requires segs.Valid() -requires 0 < segs.Seg2Len -requires PktLen(segs, 0) <= len(raw) -requires -1 <= currInfIdx && currInfIdx < 1 -requires 0 == currInfIdx ==> 0 < segs.Seg3Len -preserves acc(sl.Bytes(raw, 0, len(raw)), R56) -ensures MidSeg(raw, currInfIdx + 4, segs, 0) == +requires segs.Valid() +requires 0 < segs.Seg2Len +requires PktLen(segs, 0) <= len(raw) +requires -1 <= currInfIdx && currInfIdx < 1 +requires 0 == currInfIdx ==> 0 < segs.Seg3Len +ensures MidSeg(raw, currInfIdx + 4, segs, 0) == RightSeg(raw, currInfIdx, segs, 0) decreases -func XoverMidSeg(raw []byte, currInfIdx int, segs io.SegLens) { +func XoverMidSeg(raw seq[byte], currInfIdx int, segs io.SegLens) { midseg := reveal MidSeg(raw, currInfIdx + 4, segs, 0) rightseg := reveal RightSeg(raw, currInfIdx, segs, 0) assert midseg == rightseg } ghost -requires segs.Valid() -requires 0 < segs.Seg2Len -requires PktLen(segs, 0) <= len(raw) -requires 0 <= currInfIdx && currInfIdx < 2 -requires 0 == currInfIdx ==> currHfIdx + 1 == segs.Seg1Len -requires 1 == currInfIdx ==> 0 < segs.Seg3Len && currHfIdx + 1 == segs.Seg1Len + segs.Seg2Len -requires PktLen(segs, 0) <= len(raw) -preserves acc(sl.Bytes(raw, 0, len(raw)), R56) -preserves RightSeg(raw, currInfIdx, segs, 0) != none[io.Seg] +requires segs.Valid() +requires 0 < segs.Seg2Len +requires PktLen(segs, 0) <= len(raw) +requires 0 <= currInfIdx && currInfIdx < 2 +requires 0 == currInfIdx ==> currHfIdx + 1 == segs.Seg1Len +requires 1 == currInfIdx ==> 0 < segs.Seg3Len && currHfIdx + 1 == segs.Seg1Len + segs.Seg2Len +requires RightSeg(raw, currInfIdx, segs, 0) != none[io.Seg] +ensures RightSeg(raw, currInfIdx, segs, 0) != none[io.Seg] ensures let prevSegLen := segs.LengthOfPrevSeg(currHfIdx) in let segLen := segs.LengthOfCurrSeg(currHfIdx) in @@ -855,7 +853,7 @@ ensures len(currseg.Future) > 0 && get(RightSeg(raw, currInfIdx, segs, 0)) == absIncPathSeg(currseg) decreases -func XoverRightSeg(raw []byte, currInfIdx int, currHfIdx int, segs io.SegLens) { +func XoverRightSeg(raw seq[byte], currInfIdx int, currHfIdx int, segs io.SegLens) { prevSegLen := segs.LengthOfPrevSeg(currHfIdx) segLen := segs.LengthOfCurrSeg(currHfIdx) numInf := segs.NumInfoFields() @@ -875,28 +873,12 @@ requires 0 <= offset requires 0 <= currHfIdx && currHfIdx <= end requires end <= segLen requires offset + path.HopLen * segLen <= len(raw) -preserves acc(sl.Bytes(raw, 0, len(raw)), R54) -ensures hopFields(raw, offset, currHfIdx, segLen)[:end - currHfIdx] == - hopFields(raw, offset, currHfIdx, end) -decreases -func HopsFromSuffixOfRawMatchSuffixOfHops(raw []byte, offset int, currHfIdx int, segLen int, end int) { - hopsFromSuffixOfRawMatchSuffixOfHops(raw, offset, currHfIdx, segLen, end, R54) -} - -ghost -requires R55 < p -requires 0 <= offset -requires 0 <= currHfIdx && currHfIdx <= end -requires end <= segLen -requires offset + path.HopLen * segLen <= len(raw) -preserves acc(sl.Bytes(raw, 0, len(raw)), p) ensures hopFields(raw, offset, currHfIdx, segLen)[:end - currHfIdx] == hopFields(raw, offset, currHfIdx, end) decreases end - currHfIdx -func hopsFromSuffixOfRawMatchSuffixOfHops(raw []byte, offset int, currHfIdx int, segLen int, end int, p perm) { +func HopsFromSuffixOfRawMatchSuffixOfHops(raw seq[byte], offset int, currHfIdx int, segLen int, end int) { if (currHfIdx != end) { - newP := (p + R55)/2 - hopsFromSuffixOfRawMatchSuffixOfHops(raw, offset, currHfIdx + 1, segLen, end, newP) + HopsFromSuffixOfRawMatchSuffixOfHops(raw, offset, currHfIdx + 1, segLen, end) } } @@ -905,28 +887,12 @@ requires 0 <= offset requires 0 <= start requires 0 <= currHfIdx && currHfIdx <= segLen - start requires offset + path.HopLen * segLen <= len(raw) -preserves acc(sl.Bytes(raw, 0, len(raw)), R54) -ensures hopFields(raw, offset, currHfIdx, segLen)[start:] == - hopFields(raw, offset, currHfIdx + start, segLen) -decreases -func HopsFromPrefixOfRawMatchPrefixOfHops(raw []byte, offset int, currHfIdx int, segLen int, start int) { - hopsFromPrefixOfRawMatchPrefixOfHops(raw, offset, currHfIdx, segLen, start, R54) -} - -ghost -requires R55 < p -requires 0 <= offset -requires 0 <= start -requires 0 <= currHfIdx && currHfIdx <= segLen - start -requires offset + path.HopLen * segLen <= len(raw) -preserves acc(sl.Bytes(raw, 0, len(raw)), p) ensures hopFields(raw, offset, currHfIdx, segLen)[start:] == hopFields(raw, offset, currHfIdx + start, segLen) decreases start -func hopsFromPrefixOfRawMatchPrefixOfHops(raw []byte, offset int, currHfIdx int, segLen int, start int, p perm) { +func HopsFromPrefixOfRawMatchPrefixOfHops(raw seq[byte], offset int, currHfIdx int, segLen int, start int) { if (start != 0) { - newP := (p + R55)/2 - hopsFromPrefixOfRawMatchPrefixOfHops(raw, offset, currHfIdx, segLen, start - 1, newP) + HopsFromPrefixOfRawMatchPrefixOfHops(raw, offset, currHfIdx, segLen, start - 1) } } @@ -935,27 +901,11 @@ requires 0 <= offset requires 0 <= start && start <= currHfIdx requires 0 <= currHfIdx && currHfIdx <= segLen requires offset + path.HopLen * segLen <= len(raw) -preserves acc(sl.Bytes(raw, 0, len(raw)), R54) -ensures hopFields(raw, offset, currHfIdx, segLen) == - hopFields(raw, offset + start * path.HopLen, currHfIdx - start, segLen - start) -decreases -func AlignHopsOfRawWithOffsetAndIndex(raw []byte, offset int, currHfIdx int, segLen int, start int) { - alignHopsOfRawWithOffsetAndIndex(raw, offset, currHfIdx, segLen, start, R54) -} - -ghost -requires R55 < p -requires 0 <= offset -requires 0 <= start && start <= currHfIdx -requires 0 <= currHfIdx && currHfIdx <= segLen -requires offset + path.HopLen * segLen <= len(raw) -preserves acc(sl.Bytes(raw, 0, len(raw)), p) ensures hopFields(raw, offset, currHfIdx, segLen) == hopFields(raw, offset + start * path.HopLen, currHfIdx - start, segLen - start) decreases segLen - currHfIdx -func alignHopsOfRawWithOffsetAndIndex(raw []byte, offset int, currHfIdx int, segLen int, start int, p perm) { +func AlignHopsOfRawWithOffsetAndIndex(raw seq[byte], offset int, currHfIdx int, segLen int, start int) { if (currHfIdx != segLen) { - newP := (p + R55)/2 - alignHopsOfRawWithOffsetAndIndex(raw, offset, currHfIdx + 1, segLen, start, newP) + AlignHopsOfRawWithOffsetAndIndex(raw, offset, currHfIdx + 1, segLen, start) } -} \ No newline at end of file +} diff --git a/pkg/slayers/path/scion/widen-lemma.gobra b/pkg/slayers/path/scion/widen-lemma.gobra index 9eb8eb06f..76c5dbc78 100644 --- a/pkg/slayers/path/scion/widen-lemma.gobra +++ b/pkg/slayers/path/scion/widen-lemma.gobra @@ -16,28 +16,30 @@ package scion +// The lemmas in this file relate the abstract segments parsed from the +// view of a packet buffer to the ones parsed from the view of a prefix +// (or subrange) of that buffer. Since views are mathematical sequences, +// these lemmas require no permissions at all: subslicing a view is +// ordinary sequence slicing. + import ( - sl "verification/utils/slices" "verification/io" - . "verification/utils/definitions" - "verification/dependencies/encoding/binary" + "verification/utils/seqs" "github.com/scionproto/scion/pkg/slayers/path" ) ghost -requires 0 <= start && start <= headerOffset -requires path.InfoFieldOffset(currInfIdx, headerOffset) + path.InfoLen <= offset -requires 0 < segLen -requires offset + path.HopLen * segLen <= length -requires length <= len(raw) -requires 0 <= currHfIdx && currHfIdx <= segLen -requires 0 <= currInfIdx && currInfIdx < 3 -preserves acc(sl.Bytes(raw, 0, len(raw)), R51) -preserves acc(sl.Bytes(raw[start:length], 0, len(raw[start:length])), R51) -ensures CurrSeg(raw, offset, currInfIdx, currHfIdx, segLen, headerOffset) == +requires 0 <= start && start <= headerOffset +requires path.InfoFieldOffset(currInfIdx, headerOffset) + path.InfoLen <= offset +requires 0 < segLen +requires offset + path.HopLen * segLen <= length +requires length <= len(raw) +requires 0 <= currHfIdx && currHfIdx <= segLen +requires 0 <= currInfIdx && currInfIdx < 3 +ensures CurrSeg(raw, offset, currInfIdx, currHfIdx, segLen, headerOffset) == CurrSeg(raw[start:length], offset-start, currInfIdx, currHfIdx, segLen, headerOffset-start) decreases -func WidenCurrSeg(raw []byte, +func WidenCurrSeg(raw seq[byte], offset int, currInfIdx int, currHfIdx int, @@ -45,35 +47,13 @@ func WidenCurrSeg(raw []byte, headerOffset int, start int, length int) { - unfold acc(sl.Bytes(raw, 0, len(raw)), R53) - unfold acc(sl.Bytes(raw[start:length], 0, len(raw[start:length])), R53) - - ainfo1 := path.Timestamp(raw, currInfIdx, headerOffset) - ainfo2 := path.Timestamp(raw[start:length], currInfIdx, headerOffset-start) - sl.AssertSliceOverlap(raw, start, length) - idxTimestamp := path.InfoFieldOffset(currInfIdx, headerOffset-start)+4 - sl.AssertSliceOverlap(raw[start:length], idxTimestamp, idxTimestamp+4) - assert ainfo1 == ainfo2 - - uinfo1 := path.AbsUinfo(raw, currInfIdx, headerOffset) - uinfo2 := path.AbsUinfo(raw[start:length], currInfIdx, headerOffset-start) - idxUinfo := path.InfoFieldOffset(currInfIdx, headerOffset-start)+2 - sl.AssertSliceOverlap(raw[start:length], idxUinfo, idxUinfo+2) - assert uinfo1 == uinfo2 - - consDir1 := path.ConsDir(raw, currInfIdx, headerOffset) - consDir2 := path.ConsDir(raw[start:length], currInfIdx, headerOffset-start) - assert consDir1 == consDir2 - - peer1 := path.Peer(raw, currInfIdx, headerOffset) - peer2 := path.Peer(raw[start:length], currInfIdx, headerOffset-start) - assert peer1 == peer2 - - widenSegment(raw, offset, currHfIdx, ainfo1, uinfo1, consDir1, peer1, segLen, start, length) + infOffset := path.InfoFieldOffset(currInfIdx, headerOffset) + seqs.SubSeqOfSubSeq(raw, infOffset, infOffset + path.InfoLen, start, length) + assert InfofieldBytes(raw, currInfIdx, headerOffset) == + InfofieldBytes(raw[start:length], currInfIdx, headerOffset-start) + widenHopFields(raw, offset, 0, segLen, start, length) reveal CurrSeg(raw, offset, currInfIdx, currHfIdx, segLen, headerOffset) reveal CurrSeg(raw[start:length], offset-start, currInfIdx, currHfIdx, segLen, headerOffset-start) - fold acc(sl.Bytes(raw, 0, len(raw)), R53) - fold acc(sl.Bytes(raw[start:length], 0, len(raw[start:length])), R53) } ghost @@ -82,12 +62,10 @@ requires 0 < segLen requires 0 <= currHfIdx && currHfIdx <= segLen requires length <= len(raw) requires offset + path.HopLen * segLen <= length -preserves acc(sl.Bytes(raw, 0, len(raw)), R52) -preserves acc(sl.Bytes(raw[start:length], 0, len(raw[start:length])), R52) ensures segment(raw, offset, currHfIdx, ainfo, uinfo, consDir, peer, segLen) == segment(raw[start:length], offset-start, currHfIdx, ainfo, uinfo, consDir, peer, segLen) decreases -func widenSegment(raw []byte, +func widenSegment(raw seq[byte], offset int, currHfIdx int, ainfo io.Ainfo, @@ -97,43 +75,37 @@ func widenSegment(raw []byte, segLen int, start int, length int) { - newP := (R52 + R53)/2 - widenHopFields(raw, offset, 0, segLen, start, length, newP) + widenHopFields(raw, offset, 0, segLen, start, length) } ghost -requires R53 < p -requires 0 <= start && start <= offset -requires 0 <= currHfIdx && currHfIdx <= segLen -requires offset + path.HopLen * segLen <= length -requires length <= len(raw) -preserves acc(sl.Bytes(raw, 0, len(raw)), p) -preserves acc(sl.Bytes(raw[start:length], 0, len(raw[start:length])), p) -ensures hopFields(raw, offset, currHfIdx, segLen) == +requires 0 <= start && start <= offset +requires 0 <= currHfIdx && currHfIdx <= segLen +requires offset + path.HopLen * segLen <= length +requires length <= len(raw) +ensures hopFields(raw, offset, currHfIdx, segLen) == hopFields(raw[start:length], offset-start, currHfIdx, segLen) decreases segLen - currHfIdx -func widenHopFields(raw []byte, offset int, currHfIdx int, segLen int, start int, length int, p perm) { +func widenHopFields(raw seq[byte], offset int, currHfIdx int, segLen int, start int, length int) { if (currHfIdx != segLen) { - path.WidenBytesHopField(raw, offset + path.HopLen * currHfIdx, start, length) - hf1 := path.BytesToIO_HF(raw, 0, offset + path.HopLen * currHfIdx, len(raw)) - hf2 := path.BytesToIO_HF(raw[start:length], 0, offset + path.HopLen * currHfIdx - start, length - start) - newP := (p + R53)/2 - widenHopFields(raw, offset, currHfIdx + 1, segLen, start, length, newP) + hfStart := offset + path.HopLen * currHfIdx + seqs.SubSeqOfSubSeq(raw, hfStart, hfStart + path.HopLen, start, length) + assert raw[hfStart:hfStart + path.HopLen] == + raw[start:length][hfStart - start:hfStart - start + path.HopLen] + widenHopFields(raw, offset, currHfIdx + 1, segLen, start, length) } } ghost -requires 0 <= start && start <= headerOffset -requires segs.Valid() -requires 0 <= length && length <= len(raw) -requires PktLen(segs, headerOffset) <= length -requires 1 <= currInfIdx && currInfIdx < 4 -preserves acc(sl.Bytes(raw, 0, len(raw)), R51) -preserves acc(sl.Bytes(raw[start:length], 0, len(raw[start:length])), R51) -ensures LeftSeg(raw, currInfIdx, segs, headerOffset) == +requires 0 <= start && start <= headerOffset +requires segs.Valid() +requires 0 <= length && length <= len(raw) +requires PktLen(segs, headerOffset) <= length +requires 1 <= currInfIdx && currInfIdx < 4 +ensures LeftSeg(raw, currInfIdx, segs, headerOffset) == LeftSeg(raw[start:length], currInfIdx, segs, headerOffset-start) decreases -func WidenLeftSeg(raw []byte, +func WidenLeftSeg(raw seq[byte], currInfIdx int, segs io.SegLens, headerOffset int, @@ -152,17 +124,15 @@ func WidenLeftSeg(raw []byte, } ghost -requires 0 <= start && start <= headerOffset -requires segs.Valid() -requires 0 <= length && length <= len(raw) -requires PktLen(segs, headerOffset) <= length -requires -1 <= currInfIdx && currInfIdx < 2 -preserves acc(sl.Bytes(raw, 0, len(raw)), R51) -preserves acc(sl.Bytes(raw[start:length], 0, len(raw[start:length])), R51) -ensures RightSeg(raw, currInfIdx, segs, headerOffset) == +requires 0 <= start && start <= headerOffset +requires segs.Valid() +requires 0 <= length && length <= len(raw) +requires PktLen(segs, headerOffset) <= length +requires -1 <= currInfIdx && currInfIdx < 2 +ensures RightSeg(raw, currInfIdx, segs, headerOffset) == RightSeg(raw[start:length], currInfIdx, segs, headerOffset-start) decreases -func WidenRightSeg(raw []byte, +func WidenRightSeg(raw seq[byte], currInfIdx int, segs io.SegLens, headerOffset int, @@ -180,17 +150,15 @@ func WidenRightSeg(raw []byte, } ghost -requires 0 <= start && start <= headerOffset -requires segs.Valid() -requires 2 <= currInfIdx && currInfIdx < 5 -requires 0 <= length && length <= len(raw) -requires PktLen(segs, headerOffset) <= length -preserves acc(sl.Bytes(raw, 0, len(raw)), R51) -preserves acc(sl.Bytes(raw[start:length], 0, len(raw[start:length])), R51) -ensures MidSeg(raw, currInfIdx, segs, headerOffset) == +requires 0 <= start && start <= headerOffset +requires segs.Valid() +requires 2 <= currInfIdx && currInfIdx < 5 +requires 0 <= length && length <= len(raw) +requires PktLen(segs, headerOffset) <= length +ensures MidSeg(raw, currInfIdx, segs, headerOffset) == MidSeg(raw[start:length], currInfIdx, segs, headerOffset - start) decreases -func WidenMidSeg(raw []byte, +func WidenMidSeg(raw seq[byte], currInfIdx int, segs io.SegLens, headerOffset int, @@ -205,4 +173,4 @@ func WidenMidSeg(raw []byte, } reveal MidSeg(raw, currInfIdx, segs, headerOffset) reveal MidSeg(raw[start:length], currInfIdx, segs, headerOffset - start) -} \ No newline at end of file +} diff --git a/pkg/slayers/scion.go b/pkg/slayers/scion.go index 3b8794d3a..c832df9c6 100644 --- a/pkg/slayers/scion.go +++ b/pkg/slayers/scion.go @@ -223,7 +223,7 @@ func (s *SCION) NetworkFlow() (res gopacket.Flow) { // @ ensures e != nil ==> e.ErrorMem() // post for IO: // @ ensures e == nil && old(s.EqPathType(ubuf)) ==> -// @ IsSupportedRawPkt(b.View()) == old(IsSupportedPkt(ubuf)) +// @ IsSupportedPkt(b.View()) == old(IsSupportedPkt(sl.View(ubuf, 0, len(ubuf)))) // @ decreases func (s *SCION) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions /* @ , ghost ubuf []byte @*/) (e error) { // @ unfold acc(s.Mem(ubuf), R1) @@ -263,55 +263,60 @@ func (s *SCION) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeO buf[9] = uint8(s.DstAddrType&0x7)<<4 | uint8(s.SrcAddrType&0x7) // @ assert &buf[10:12][0] == &buf[10] && &buf[10:12][1] == &buf[11] binary.BigEndian.PutUint16(buf[10:12], 0) + // @ assert &buf[4] == &uSerBufN[4] && &buf[8] == &uSerBufN[8] + // @ ghost b4 := buf[4] + // @ ghost b8 := buf[8] // @ fold acc(sl.Bytes(uSerBufN, 0, len(uSerBufN)), writePerm) + // the GetByte terms below instantiate the preservation + // postconditions of ViewElems, which carry the byte values of the + // buffer across the lemma call + // @ assert sl.GetByte(uSerBufN, 0, len(uSerBufN), 4) == b4 + // @ assert sl.GetByte(uSerBufN, 0, len(uSerBufN), 8) == b8 + // @ sl.ViewElems(uSerBufN, 0, len(uSerBufN), writePerm) + // @ ghost vSer0 := sl.View(uSerBufN, 0, len(uSerBufN)) + // @ assert vSer0[4] == sl.GetByte(uSerBufN, 0, len(uSerBufN), 4) + // @ assert vSer0[8] == sl.GetByte(uSerBufN, 0, len(uSerBufN), 8) + // @ assert vSer0[4] == b4 && vSer0[8] == b8 // @ ghost if s.EqPathType(ubuf) { - // @ assert reveal s.EqPathTypeWithBuffer(ubuf, uSerBufN) - // @ s.IsSupportedPktLemma(ubuf, uSerBufN) + // @ assert reveal s.EqPathTypeWithBuffer(ubuf, vSer0) + // @ s.IsSupportedPktLemma(ubuf, vSer0) // @ } + // @ IsSupportedPktSubslice(vSer0, CmnHdrLen) // Serialize address header. - // @ sl.SplitRange_Bytes(uSerBufN, CmnHdrLen, scnLen, HalfPerm) - // @ sl.Reslice_Bytes(uSerBufN, 0, CmnHdrLen, R54) - // @ IsSupportedPktSubslice(uSerBufN, CmnHdrLen) - // @ sl.SplitRange_Bytes(uSerBufN, CmnHdrLen, scnLen, HalfPerm) + // @ sl.SplitRange_Bytes(uSerBufN, CmnHdrLen, scnLen, writePerm) // @ sl.SplitRange_Bytes(ubuf, CmnHdrLen, len(ubuf), R10) if err := s.SerializeAddrHdr(buf[CmnHdrLen:] /*@ , ubuf[CmnHdrLen:] @*/); err != nil { - // @ sl.Unslice_Bytes(uSerBufN, 0, CmnHdrLen, R54) // @ sl.CombineRange_Bytes(uSerBufN, CmnHdrLen, scnLen, writePerm) // @ sl.CombineRange_Bytes(ubuf, CmnHdrLen, len(ubuf), R10) return err } offset := CmnHdrLen + s.AddrHdrLen( /*@ nil, true @*/ ) - // @ sl.CombineRange_Bytes(uSerBufN, CmnHdrLen, scnLen, HalfPerm) + // @ sl.CombineRangeWithViews_Bytes(uSerBufN, CmnHdrLen, scnLen, writePerm, sl.View(uSerBufN, 0, CmnHdrLen), sl.View(uSerBufN[CmnHdrLen:scnLen], 0, (scnLen)-(CmnHdrLen)), sl.View(uSerBufN, scnLen, len(uSerBufN))) // @ sl.CombineRange_Bytes(ubuf, CmnHdrLen, len(ubuf), R10) - // @ IsSupportedPktSubslice(uSerBufN, CmnHdrLen) - // @ sl.Unslice_Bytes(uSerBufN, 0, CmnHdrLen, R54) - // @ sl.CombineRange_Bytes(uSerBufN, CmnHdrLen, scnLen, HalfPerm) + // @ ghost vSerA := sl.View(uSerBufN, 0, len(uSerBufN)) + // @ assert vSerA[:CmnHdrLen] == vSer0[:CmnHdrLen] + // @ IsSupportedPktSubslice(vSerA, CmnHdrLen) + // @ assert IsSupportedPkt(vSerA) == IsSupportedPkt(vSer0) // Serialize path header. // @ ghost startP := int(CmnHdrLen+s.AddrHdrLenSpecInternal()) // @ ghost endP := int(s.HdrLen*LineLen) // @ ghost pathSlice := ubuf[startP : endP] - // @ sl.SplitRange_Bytes(uSerBufN, offset, scnLen, HalfPerm) - // @ sl.SplitRange_Bytes(ubuf, startP, endP, HalfPerm) - // @ sl.Reslice_Bytes(uSerBufN, 0, offset, R54) - // @ sl.Reslice_Bytes(ubuf, 0, startP, R54) - // @ IsSupportedPktSubslice(uSerBufN, offset) - // @ IsSupportedPktSubslice(ubuf, startP) - // @ sl.SplitRange_Bytes(uSerBufN, offset, scnLen, HalfPerm) - // @ sl.SplitRange_Bytes(ubuf, startP, endP, HalfPerm) + // @ IsSupportedPktSubslice(vSerA, offset) + // @ sl.SplitRange_Bytes(uSerBufN, offset, scnLen, writePerm) + // @ sl.SplitRange_Bytes(ubuf, startP, endP, writePerm) tmp := s.Path.SerializeTo(buf[offset:] /*@, pathSlice @*/) - // @ sl.CombineRange_Bytes(uSerBufN, offset, scnLen, HalfPerm) - // @ sl.CombineRange_Bytes(ubuf, startP, endP, HalfPerm) - // @ IsSupportedPktSubslice(uSerBufN, offset) - // @ IsSupportedPktSubslice(ubuf, startP) - // @ sl.Unslice_Bytes(uSerBufN, 0, offset, R54) - // @ sl.Unslice_Bytes(ubuf, 0, startP, R54) - // @ sl.CombineRange_Bytes(uSerBufN, offset, scnLen, HalfPerm) - // @ sl.CombineRange_Bytes(ubuf, startP, endP, HalfPerm) - // @ reveal IsSupportedPkt(uSerBufN) - // @ reveal IsSupportedRawPkt(b.View()) + // @ sl.CombineRangeWithViews_Bytes(uSerBufN, offset, scnLen, writePerm, sl.View(uSerBufN, 0, offset), sl.View(uSerBufN[offset:scnLen], 0, (scnLen)-(offset)), sl.View(uSerBufN, scnLen, len(uSerBufN))) + // @ sl.CombineRange_Bytes(ubuf, startP, endP, writePerm) + // @ ghost vSer1 := sl.View(uSerBufN, 0, len(uSerBufN)) + // @ assert vSer1[:offset] == vSerA[:offset] + // @ assert vSer1[:CmnHdrLen] == vSerA[:CmnHdrLen] + // @ IsSupportedPktSubslice(vSer1, offset) + // @ assert IsSupportedPkt(vSer1) == IsSupportedPkt(vSerA) + // @ assert b.View() == vSer1 + // @ reveal IsSupportedPkt(b.View()) return tmp } @@ -328,6 +333,7 @@ func (s *SCION) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeO // @ ensures res == nil ==> s.EqPathType(data) // @ ensures res != nil ==> s.NonInitMem() && res.ErrorMem() // @ decreases +// @ #backend[exhaleMode(1)] func (s *SCION) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) (res error) { // Decode common header. if len(data) < CmnHdrLen { @@ -353,14 +359,19 @@ func (s *SCION) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) (res er // @ preserves CmnHdrLen <= len(data) && acc(sl.Bytes(data, 0, len(data)), R41) // @ ensures s.DstAddrType.Has3Bits() && s.SrcAddrType.Has3Bits() // @ ensures 0 <= s.PathType && s.PathType < 256 - // @ ensures path.Type(GetPathType(data)) == s.PathType - // @ ensures L4ProtocolType(GetNextHdr(data)) == s.NextHdr - // @ ensures GetLength(data) == int(s.HdrLen * LineLen) - // @ ensures GetAddressOffset(data) == + // @ ensures path.Type(GetPathType(sl.View(data, 0, len(data)))) == s.PathType + // @ ensures L4ProtocolType(GetNextHdr(sl.View(data, 0, len(data)))) == s.NextHdr + // @ ensures GetLength(sl.View(data, 0, len(data))) == int(s.HdrLen * LineLen) + // @ ensures GetAddressOffset(sl.View(data, 0, len(data))) == // @ CmnHdrLen + 2*addr.IABytes + s.DstAddrType.Length() + s.SrcAddrType.Length() // @ decreases // @ outline( - // @ unfold acc(sl.Bytes(data, 0, len(data)), R41) + // @ ghost v := sl.View(data, 0, len(data)) + // @ sl.ViewElems(data, 0, len(data), R42) + // unfolding only part of the held fraction pins the view of data: + // the retained instance is untouched, so the view after refolding + // is the same as the captured one + // @ unfold acc(sl.Bytes(data, 0, len(data)), R42) s.NextHdr = L4ProtocolType(data[4]) s.HdrLen = data[5] // @ assert &data[6:8][0] == &data[6] && &data[6:8][1] == &data[7] @@ -372,7 +383,9 @@ func (s *SCION) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) (res er // @ assert int(s.DstAddrType) == b.BitAnd7(int(data[9] >> 4)) s.SrcAddrType = AddrType(data[9] & 0x7) // @ assert int(s.SrcAddrType) == b.BitAnd7(int(data[9])) - // @ fold acc(sl.Bytes(data, 0, len(data)), R41) + // @ assert v[4] == data[4] && v[5] == data[5] && v[8] == data[8] && v[9] == data[9] + // @ fold acc(sl.Bytes(data, 0, len(data)), R42) + // @ assert sl.View(data, 0, len(data)) == v // @ ) // Decode address header. // @ sl.SplitByIndex_Bytes(data, 0, len(data), CmnHdrLen, R41) @@ -433,14 +446,13 @@ func (s *SCION) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) (res er s.Payload = data[hdrBytes:] // @ fold acc(s.Mem(data), R54) // @ ghost if(typeOf(s.GetPath(data)) == (*scion.Raw)) { - // @ unfold acc(sl.Bytes(data, 0, len(data)), R56) - // @ unfold acc(sl.Bytes(data[offset : offset+pathLen], 0, len(data[offset : offset+pathLen])), R56) + // @ sl.ViewOfSubslice(data, offset, offset+pathLen, R56) + // @ assert sl.View(data[offset : offset+pathLen], 0, pathLen) == + // @ sl.View(data, 0, len(data))[offset : offset+pathLen] // @ unfold acc(s.Path.(*scion.Raw).Mem(data[offset : offset+pathLen]), R55) // @ assert reveal s.EqAbsHeader(data) // @ assert reveal s.ValidScionInitSpec(data) // @ fold acc(s.Path.Mem(data[offset : offset+pathLen]), R55) - // @ fold acc(sl.Bytes(data, 0, len(data)), R56) - // @ fold acc(sl.Bytes(data[offset : offset+pathLen], 0, len(data[offset : offset+pathLen])), R56) // @ } // @ sl.CombineRange_Bytes(data, offset, offset+pathLen, R41) // @ assert typeOf(s.GetPath(data)) == *scion.Raw ==> s.EqAbsHeader(data) && s.ValidScionInitSpec(data) diff --git a/pkg/slayers/scion_spec.gobra b/pkg/slayers/scion_spec.gobra index 636713ec1..07205fc03 100644 --- a/pkg/slayers/scion_spec.gobra +++ b/pkg/slayers/scion_spec.gobra @@ -31,7 +31,6 @@ import ( sl "verification/utils/slices" "verification/io" "encoding/binary" - "verification/utils/seqs" ) pred PathPoolMem(pathPool []path.Path, pathPoolRaw path.Path) { @@ -354,52 +353,37 @@ pure func (s *SCION) GetPath(ub []byte) path.Path { ghost opaque requires s.Mem(ub) -requires sl.Bytes(ub, 0, length) -requires CmnHdrLen <= length +requires CmnHdrLen <= len(raw) decreases -pure func (s *SCION) ValidHeaderOffset(ub []byte, length int) bool { - return GetAddressOffsetWithinLength(ub, length) == s.PathStartIdx(ub) && - GetLengthWithinLength(ub,length) == s.PathEndIdx(ub) +pure func (s *SCION) ValidHeaderOffset(ub []byte, raw seq[byte]) bool { + return GetAddressOffset(raw) == s.PathStartIdx(ub) && + GetLength(raw) == s.PathEndIdx(ub) } ghost requires acc(s.Mem(ub), R56) -requires acc(sl.Bytes(ub, 0, len(ub)), R55) -requires acc(sl.Bytes(ub, 0, length), R55) -requires CmnHdrLen <= length && length <= len(ub) -requires s.ValidHeaderOffset(ub, len(ub)) +requires CmnHdrLen <= length && length <= len(raw) +requires s.ValidHeaderOffset(ub, raw) ensures acc(s.Mem(ub), R56) -ensures acc(sl.Bytes(ub, 0, len(ub)), R55) -ensures acc(sl.Bytes(ub, 0, length), R55) -ensures s.ValidHeaderOffset(ub, length) +ensures s.ValidHeaderOffset(ub, raw[:length]) decreases -func (s *SCION) ValidHeaderOffsetToSubSliceLemma(ub []byte, length int) { - reveal s.ValidHeaderOffset(ub, len(ub)) - unfold acc(sl.Bytes(ub, 0, len(ub)), R56) - unfold acc(sl.Bytes(ub, 0, length), R56) - assert reveal s.ValidHeaderOffset(ub, length) - fold acc(sl.Bytes(ub, 0, len(ub)), R56) - fold acc(sl.Bytes(ub, 0, length), R56) +func (s *SCION) ValidHeaderOffsetToSubSliceLemma(ub []byte, raw seq[byte], length int) { + reveal s.ValidHeaderOffset(ub, raw) + assert raw[:length][5] == raw[5] && raw[:length][9] == raw[9] + assert reveal s.ValidHeaderOffset(ub, raw[:length]) } ghost requires acc(s.Mem(ub), R56) -requires acc(sl.Bytes(ub, 0, len(ub)), R55) -requires acc(sl.Bytes(ub, 0, length), R55) -requires CmnHdrLen <= length && length <= len(ub) -requires s.ValidHeaderOffset(ub, length) +requires CmnHdrLen <= length && length <= len(raw) +requires s.ValidHeaderOffset(ub, raw[:length]) ensures acc(s.Mem(ub), R56) -ensures acc(sl.Bytes(ub, 0, len(ub)), R55) -ensures acc(sl.Bytes(ub, 0, length), R55) -ensures s.ValidHeaderOffset(ub, len(ub)) +ensures s.ValidHeaderOffset(ub, raw) decreases -func (s *SCION) ValidHeaderOffsetFromSubSliceLemma(ub []byte, length int) { - reveal s.ValidHeaderOffset(ub, len(ub)) - unfold acc(sl.Bytes(ub, 0, len(ub)), R56) - unfold acc(sl.Bytes(ub, 0, length), R56) - assert reveal s.ValidHeaderOffset(ub, length) - fold acc(sl.Bytes(ub, 0, len(ub)), R56) - fold acc(sl.Bytes(ub, 0, length), R56) +func (s *SCION) ValidHeaderOffsetFromSubSliceLemma(ub []byte, raw seq[byte], length int) { + reveal s.ValidHeaderOffset(ub, raw[:length]) + assert raw[:length][5] == raw[5] && raw[:length][9] == raw[9] + assert reveal s.ValidHeaderOffset(ub, raw) } ghost @@ -413,24 +397,15 @@ pure func (s *SCION) EqAbsHeader(ub []byte) bool { // parsing errors (since the SIF PR in Gobra, low is a keyword). let low_ := CmnHdrLen+s.AddrHdrLenSpecInternal() in let high := int(s.HdrLen) * LineLen in - GetAddressOffset(ub) == low_ && - GetLength(ub) == int(high) && + let v := sl.View(ub, 0, len(ub)) in + GetAddressOffset(v) == low_ && + GetLength(v) == int(high) && // Might be worth introducing EqAbsHeader as an interface method on Path // to avoid doing these casts, especially when we add support for EPIC. typeOf(s.Path) == (*scion.Raw) && unfolding s.Path.Mem(ub[low_:high]) in - unfolding sl.Bytes(ub, 0, len(ub)) in - let _ := Asserting(forall k int :: {&ub[low_:high][k]} 0 <= k && k < high ==> - &ub[low_:high][k] == &ub[low_ + k]) in - let _ := Asserting(forall k int :: {&ub[low_:high][:scion.MetaLen][k]} 0 <= k && k < scion.MetaLen ==> - &ub[low_:high][:scion.MetaLen][k] == &ub[low_:high][k]) in - let metaHdr := scion.DecodedFrom(binary.BigEndian.Uint32(ub[low_:high][:scion.MetaLen])) in - let seg1 := int(metaHdr.SegLen[0]) in - let seg2 := int(metaHdr.SegLen[1]) in - let seg3 := int(metaHdr.SegLen[2]) in - let segs := io.CombineSegLens(seg1, seg2, seg3) in s.Path.(*scion.Raw).Base.GetBase() == - scion.Base{metaHdr, segs.NumInfoFields(), segs.TotalHops()} + scion.RawBytesToBase(v[low_:high]) } // Describes a SCION packet that was successfully decoded by `DecodeFromBytes`. @@ -451,19 +426,15 @@ pure func (s *SCION) ValidScionInitSpec(ub []byte) bool { // Checks if the common path header is valid in the serialized scion packet. ghost opaque -requires sl.Bytes(raw, 0, len(raw)) decreases -pure func ValidPktMetaHdr(raw []byte) bool { +pure func ValidPktMetaHdr(raw seq[byte]) bool { return CmnHdrLen <= len(raw) && let start := GetAddressOffset(raw) in let end := start+scion.MetaLen in 0 <= start && end <= len(raw) && - let rawHdr := raw[start:end] in let length := GetLength(raw) in length <= len(raw) && - unfolding sl.Bytes(raw, 0, len(raw)) in - let _ := Asserting(forall k int :: {&rawHdr[k]} 0 <= k && k < scion.MetaLen ==> &rawHdr[k] == &raw[start + k]) in - let hdr := binary.BigEndian.Uint32(rawHdr) in + let hdr := binary.BigEndian.Uint32Spec(raw[start], raw[start+1], raw[start+2], raw[start+3]) in let metaHdr := scion.DecodedFrom(hdr) in let seg1 := int(metaHdr.SegLen[0]) in let seg2 := int(metaHdr.SegLen[1]) in @@ -477,109 +448,66 @@ pure func ValidPktMetaHdr(raw []byte) bool { ghost opaque -requires sl.Bytes(raw, 0, len(raw)) decreases -pure func IsSupportedPkt(raw []byte) bool { +pure func IsSupportedPkt(raw seq[byte]) bool { return CmnHdrLen <= len(raw) && - let pathType := path.Type(GetPathType(raw)) in - let nextHdr := L4ProtocolType(GetNextHdr(raw)) in - pathType == scion.PathType && - nextHdr != L4SCMP -} - -ghost -opaque -decreases -pure func IsSupportedRawPkt(raw seq[byte]) bool { - return CmnHdrLen <= len(raw) && - let pathType := path.Type(raw[8]) in + let pathType := path.Type(raw[8]) in let nextHdr := L4ProtocolType(raw[4]) in pathType == scion.PathType && nextHdr != L4SCMP } ghost -requires CmnHdrLen <= idx && idx <= len(raw) -preserves acc(sl.Bytes(raw, 0, len(raw)), R55) -preserves acc(sl.Bytes(raw[:idx], 0, idx), R55) -ensures IsSupportedPkt(raw) == IsSupportedPkt(raw[:idx]) +requires CmnHdrLen <= idx && idx <= len(raw) +ensures IsSupportedPkt(raw) == IsSupportedPkt(raw[:idx]) decreases -func IsSupportedPktSubslice(raw []byte, idx int) { - unfold acc(sl.Bytes(raw, 0, len(raw)), R56) - unfold acc(sl.Bytes(raw[:idx], 0, idx), R56) +func IsSupportedPktSubslice(raw seq[byte], idx int) { reveal IsSupportedPkt(raw) reveal IsSupportedPkt(raw[:idx]) - fold acc(sl.Bytes(raw, 0, len(raw)), R56) - fold acc(sl.Bytes(raw[:idx], 0, idx), R56) } ghost preserves acc(s.Mem(ub), R55) preserves acc(sl.Bytes(ub, 0, len(ub)), R55) -preserves acc(sl.Bytes(buffer, 0, len(buffer)), R55) preserves s.EqPathType(ub) preserves s.EqPathTypeWithBuffer(ub, buffer) -ensures IsSupportedPkt(ub) == IsSupportedPkt(buffer) +ensures IsSupportedPkt(sl.View(ub, 0, len(ub))) == IsSupportedPkt(buffer) decreases -func (s *SCION) IsSupportedPktLemma(ub []byte, buffer []byte) { +func (s *SCION) IsSupportedPktLemma(ub []byte, buffer seq[byte]) { reveal s.EqPathType(ub) reveal s.EqPathTypeWithBuffer(ub, buffer) - reveal IsSupportedPkt(ub) + reveal IsSupportedPkt(sl.View(ub, 0, len(ub))) reveal IsSupportedPkt(buffer) } ghost -requires sl.Bytes(ub, 0, len(ub)) -requires CmnHdrLen <= len(ub) +requires CmnHdrLen <= len(raw) decreases -pure func GetAddressOffset(ub []byte) int { - return GetAddressOffsetWithinLength(ub, len(ub)) -} - -ghost -requires sl.Bytes(ub, 0, length) -requires CmnHdrLen <= length -decreases -pure func GetAddressOffsetWithinLength(ub []byte, length int) int { - return unfolding sl.Bytes(ub, 0, length) in - let dstAddrLen := AddrType(ub[9] >> 4 & 0x7).Length() in - let srcAddrLen := AddrType(ub[9] & 0x7).Length() in +pure func GetAddressOffset(raw seq[byte]) int { + return let dstAddrLen := AddrType(raw[9] >> 4 & 0x7).Length() in + let srcAddrLen := AddrType(raw[9] & 0x7).Length() in CmnHdrLen + 2*addr.IABytes + dstAddrLen + srcAddrLen } ghost -requires sl.Bytes(ub, 0, len(ub)) -requires CmnHdrLen <= len(ub) -decreases -pure func GetLength(ub []byte) int { - return GetLengthWithinLength(ub, len(ub)) -} - -ghost -requires sl.Bytes(ub, 0, length) -requires CmnHdrLen <= length +requires CmnHdrLen <= len(raw) decreases -pure func GetLengthWithinLength(ub []byte, length int) int { - return unfolding sl.Bytes(ub, 0, length) in - int(ub[5]) * LineLen +pure func GetLength(raw seq[byte]) int { + return int(raw[5]) * LineLen } ghost -requires sl.Bytes(ub, 0, len(ub)) -requires CmnHdrLen <= len(ub) +requires CmnHdrLen <= len(raw) decreases -pure func GetPathType(ub []byte) int { - return unfolding sl.Bytes(ub, 0, len(ub)) in - int(ub[8]) +pure func GetPathType(raw seq[byte]) int { + return int(raw[8]) } ghost -requires sl.Bytes(ub, 0, len(ub)) -requires CmnHdrLen <= len(ub) +requires CmnHdrLen <= len(raw) decreases -pure func GetNextHdr(ub []byte) int { - return unfolding sl.Bytes(ub, 0, len(ub)) in - int(ub[4]) +pure func GetNextHdr(raw seq[byte]) int { + return int(raw[4]) } ghost @@ -588,15 +516,14 @@ requires s.Mem(ub) requires sl.Bytes(ub, 0, len(ub)) decreases pure func (s *SCION) EqPathType(ub []byte) bool { - return reveal s.EqPathTypeWithBuffer(ub, ub) + return reveal s.EqPathTypeWithBuffer(ub, sl.View(ub, 0, len(ub))) } ghost opaque requires s.Mem(ub) -requires sl.Bytes(buffer, 0, len(buffer)) decreases -pure func (s *SCION) EqPathTypeWithBuffer(ub []byte, buffer []byte) bool { +pure func (s *SCION) EqPathTypeWithBuffer(ub []byte, buffer seq[byte]) bool { return unfolding s.Mem(ub) in CmnHdrLen <= len(buffer) && path.Type(GetPathType(buffer)) == s.PathType && diff --git a/router/dataplane.go b/router/dataplane.go index 6d3d88d5d..e8ab03001 100644 --- a/router/dataplane.go +++ b/router/dataplane.go @@ -1082,10 +1082,10 @@ func (d *DataPlane) Run(ctx context.Context /*@, ghost place io.Place, ghost sta // @ assert p.N <= len(p.Buffers[0]) // @ sl.SplitRange_Bytes(p.Buffers[0], 0, p.N, HalfPerm) tmpBuf := p.Buffers[0][:p.N] - // @ ghost absPktTmpBuf := absIO_val(tmpBuf, ingressID) - // @ ghost absPktBuf0 := absIO_val(msgs[i0].Buffers[0], ingressID) + // @ ghost absPktTmpBuf := absIO_val(sl.View(tmpBuf, 0, len(tmpBuf)), ingressID) + // @ ghost absPktBuf0 := absIO_val(sl.View(msgs[i0].Buffers[0], 0, len(msgs[i0].Buffers[0])), ingressID) // @ assert msgs[i0] === p - // @ absIO_valWidenLemma(p.Buffers[0], ingressID, p.N) + // @ absIO_valWidenLemma(sl.View(p.Buffers[0], 0, len(p.Buffers[0])), ingressID, p.N) // @ assert absPktTmpBuf.isValPkt ==> absPktTmpBuf === absPktBuf0 // @ MultiElemWitnessStep(ioSharedArg.IBufY, ioIngressID, ioValSeq, i0) // @ assert ioValSeq[i0].isValPkt ==> @@ -1170,10 +1170,10 @@ func (d *DataPlane) Run(ctx context.Context /*@, ghost place io.Place, ghost sta writeMsgs[0].Addr = result.OutAddr } // @ sl.NilAcc_Bytes() - // @ assert absIO_val(result.OutPkt, result.EgressID) == - // @ absIO_val(writeMsgs[0].Buffers[0], result.EgressID) + // @ assert absIO_val(sl.View(result.OutPkt, 0, len(result.OutPkt)), result.EgressID) == + // @ absIO_val(sl.View(writeMsgs[0].Buffers[0], 0, len(writeMsgs[0].Buffers[0])), result.EgressID) // @ assert result.OutPkt != nil ==> newAbsPkt == - // @ absIO_val(writeMsgs[0].Buffers[0], result.EgressID) + // @ absIO_val(sl.View(writeMsgs[0].Buffers[0], 0, len(writeMsgs[0].Buffers[0])), result.EgressID) // @ fold acc(writeMsgs[0].Mem(), R50) // @ ghost ioLock.Lock() // @ unfold SharedInv{dp, ioSharedArg}() @@ -1567,10 +1567,10 @@ func (p *scionPacketProcessor) reset() (err error) { // @ requires dp.Valid() // @ requires acc(ioLock.LockP(), _) // @ requires ioLock.LockInv() == SharedInv{dp, ioSharedArg} -// @ requires let absPkt := absIO_val(rawPkt, p.getIngressID()) in +// @ requires let absPkt := absIO_val(sl.View(rawPkt, 0, len(rawPkt)), p.getIngressID()) in // @ absPkt.isValPkt ==> ElemWitness(ioSharedArg.IBufY, path.ifsToIO_ifs(p.getIngressID()), absPkt.ValPkt_2) // @ ensures respr.OutPkt != nil ==> -// @ newAbsPkt == absIO_val(respr.OutPkt, respr.EgressID) +// @ newAbsPkt == absIO_val(sl.View(respr.OutPkt, 0, len(respr.OutPkt)), respr.EgressID) // @ ensures (respr.OutPkt == nil) == (newAbsPkt == io.ValUnit{}) // @ ensures newAbsPkt.isValPkt ==> // @ ElemWitness(ioSharedArg.OBufY, newAbsPkt.ValPkt_1, newAbsPkt.ValPkt_2) @@ -1681,12 +1681,12 @@ func (p *scionPacketProcessor) processPkt(rawPkt []byte, // @ sl.CombineRange_Bytes(ub, start, end, HalfPerm) // @ ghost if lastLayerIdx >= 0 && !offsets[lastLayerIdx].isNil { // @ o := offsets[lastLayerIdx] - // @ sl.CombineRange_Bytes(p.rawPkt, o.start, o.end, HalfPerm) + // @ sl.CombineRangeWithViews_Bytes(p.rawPkt, o.start, o.end, HalfPerm, sl.View(p.rawPkt, 0, o.start), sl.View(p.rawPkt[o.start:o.end], 0, (o.end)-(o.start)), sl.View(p.rawPkt, o.end, len(p.rawPkt))) // @ } // @ assert sl.Bytes(p.rawPkt, 0, len(p.rawPkt)) // @ unfold acc(p.d.Mem(), _) // @ assert reveal p.scionLayer.EqPathType(p.rawPkt) - // @ assert !(reveal slayers.IsSupportedPkt(p.rawPkt)) + // @ assert !(reveal slayers.IsSupportedPkt(sl.View(p.rawPkt, 0, len(p.rawPkt)))) v1, v2 /*@, aliasesPkt, newAbsPkt @*/ := p.processOHP() // @ ResetDecodingLayers(&p.scionLayer, &p.hbhLayer, &p.e2eLayer, ubScionLayer, ubHbhLayer, ubE2eLayer, true, hasHbhLayer, hasE2eLayer) // @ fold p.sInit() @@ -1879,12 +1879,12 @@ func (p *scionPacketProcessor) processIntraBFD(data []byte) (res error) { // @ requires p.scionLayer.EqPathType(ub) // @ requires acc(ioLock.LockP(), _) // @ requires ioLock.LockInv() == SharedInv{dp, ioSharedArg} -// @ requires let absPkt := absIO_val(p.rawPkt, p.ingressID) in +// @ requires let absPkt := absIO_val(sl.View(p.rawPkt, 0, len(p.rawPkt)), p.ingressID) in // @ absPkt.isValPkt ==> ElemWitness(ioSharedArg.IBufY, path.ifsToIO_ifs(p.ingressID), absPkt.ValPkt_2) // @ ensures reserr == nil && newAbsPkt.isValPkt ==> // @ ElemWitness(ioSharedArg.OBufY, newAbsPkt.ValPkt_1, newAbsPkt.ValPkt_2) // @ ensures respr.OutPkt != nil ==> -// @ newAbsPkt == absIO_val(respr.OutPkt, respr.EgressID) +// @ newAbsPkt == absIO_val(sl.View(respr.OutPkt, 0, len(respr.OutPkt)), respr.EgressID) // @ ensures reserr != nil && respr.OutPkt != nil ==> // @ newAbsPkt.isValUnsupported // @ ensures (respr.OutPkt == nil) == (newAbsPkt == io.ValUnit{}) @@ -2033,7 +2033,7 @@ type macBuffersT struct { // @ respr.OutPkt === p.buffer.UBuf() // @ ensures reserr != nil && reserr.ErrorMem() // @ ensures respr.OutPkt != nil ==> -// @ !slayers.IsSupportedPkt(respr.OutPkt) +// @ !slayers.IsSupportedPkt(sl.View(respr.OutPkt, 0, len(respr.OutPkt))) // @ decreases func (p *scionPacketProcessor) packSCMP( typ slayers.SCMPType, @@ -2116,13 +2116,13 @@ func (p *scionPacketProcessor) packSCMP( // @ ensures reserr != nil ==> reserr.ErrorMem() // Postconditions for IO: // @ ensures reserr == nil ==> -// @ slayers.ValidPktMetaHdr(ub) && +// @ slayers.ValidPktMetaHdr(sl.View(ub, 0, len(ub))) && // @ p.scionLayer.EqAbsHeader(ub) && // @ p.scionLayer.ValidPathMetaData(ub) -// @ ensures reserr == nil ==> absPkt(ub).PathNotFullyTraversed() -// @ ensures reserr == nil ==> p.EqAbsHopField(absPkt(ub)) -// @ ensures reserr == nil ==> p.EqAbsInfoField(absPkt(ub)) -// @ ensures old(slayers.IsSupportedPkt(ub)) == slayers.IsSupportedPkt(ub) +// @ ensures reserr == nil ==> absPkt(sl.View(ub, 0, len(ub))).PathNotFullyTraversed() +// @ ensures reserr == nil ==> p.EqAbsHopField(absPkt(sl.View(ub, 0, len(ub)))) +// @ ensures reserr == nil ==> p.EqAbsInfoField(absPkt(sl.View(ub, 0, len(ub)))) +// @ ensures old(slayers.IsSupportedPkt(sl.View(ub, 0, len(ub)))) == slayers.IsSupportedPkt(sl.View(ub, 0, len(ub))) // @ ensures respr.OutPkt == nil // @ decreases func (p *scionPacketProcessor) parsePath( /*@ ghost ub []byte @*/ ) (respr processResult, reserr error) { @@ -2174,15 +2174,15 @@ func (p *scionPacketProcessor) parsePath( /*@ ghost ub []byte @*/ ) (respr proce // @ p.EstablishEqAbsHeader(ub, startP, endP) // @ p.path.EstablishValidPktMetaHdr(ubPath) // @ p.SubSliceAbsPktToAbsPkt(ub, startP, endP) - // @ absPktFutureLemma(ub) + // @ absPktFutureLemma(sl.View(ub, 0, len(ub))) // @ p.path.DecodingLemma(ubPath, p.infoField, p.hopField) - // @ assert reveal p.path.EqAbsInfoField(p.path.absPkt(ubPath), + // @ assert reveal p.path.EqAbsInfoField(p.path.absPkt(sl.View(ubPath, 0, len(ubPath))), // @ p.infoField.ToAbsInfoField()) - // @ assert reveal p.path.EqAbsHopField(p.path.absPkt(ubPath), + // @ assert reveal p.path.EqAbsHopField(p.path.absPkt(sl.View(ubPath, 0, len(ubPath))), // @ p.hopField.Abs()) - // @ assert reveal p.EqAbsHopField(absPkt(ub)) - // @ assert reveal p.EqAbsInfoField(absPkt(ub)) - // @ assert old(reveal slayers.IsSupportedPkt(ub)) == reveal slayers.IsSupportedPkt(ub) + // @ assert reveal p.EqAbsHopField(absPkt(sl.View(ub, 0, len(ub)))) + // @ assert reveal p.EqAbsInfoField(absPkt(sl.View(ub, 0, len(ub)))) + // @ assert old(reveal slayers.IsSupportedPkt(sl.View(ub, 0, len(ub)))) == reveal slayers.IsSupportedPkt(sl.View(ub, 0, len(ub))) return processResult{}, nil } @@ -2196,8 +2196,8 @@ func (p *scionPacketProcessor) parsePath( /*@ ghost ub []byte @*/ ) (respr proce // @ requires acc(&p.buffer, R50) && p.buffer != nil && p.buffer.Mem() // @ requires sl.Bytes(p.buffer.UBuf(), 0, len(p.buffer.UBuf())) // pres for IO: -// @ requires slayers.ValidPktMetaHdr(ubScionL) && p.scionLayer.EqAbsHeader(ubScionL) -// @ requires absPkt(ubScionL).PathNotFullyTraversed() +// @ requires slayers.ValidPktMetaHdr(sl.View(ubScionL, 0, len(ubScionL))) && p.scionLayer.EqAbsHeader(ubScionL) +// @ requires absPkt(sl.View(ubScionL, 0, len(ubScionL))).PathNotFullyTraversed() // @ preserves ubLL == nil || ubLL === ubScionL[startLL:endLL] // @ preserves acc(&p.lastLayer, R55) && p.lastLayer != nil // @ preserves &p.scionLayer !== p.lastLayer ==> @@ -2220,12 +2220,12 @@ func (p *scionPacketProcessor) parsePath( /*@ ghost ub []byte @*/ ) (respr proce // @ ensures reserr == nil ==> // @ respr === processResult{} // posts for IO: -// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(ubScionL) && p.scionLayer.EqAbsHeader(ubScionL) -// @ ensures reserr == nil ==> absPkt(ubScionL).PathNotFullyTraversed() -// @ ensures reserr == nil ==> absPkt(ubScionL) == old(absPkt(ubScionL)) -// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(ubScionL)) == slayers.IsSupportedPkt(ubScionL) +// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(sl.View(ubScionL, 0, len(ubScionL))) && p.scionLayer.EqAbsHeader(ubScionL) +// @ ensures reserr == nil ==> absPkt(sl.View(ubScionL, 0, len(ubScionL))).PathNotFullyTraversed() +// @ ensures reserr == nil ==> absPkt(sl.View(ubScionL, 0, len(ubScionL))) == old(absPkt(sl.View(ubScionL, 0, len(ubScionL)))) +// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(sl.View(ubScionL, 0, len(ubScionL)))) == slayers.IsSupportedPkt(sl.View(ubScionL, 0, len(ubScionL))) // @ ensures reserr != nil && respr.OutPkt != nil ==> -// @ absIO_val(respr.OutPkt, respr.EgressID).isValUnsupported +// @ absIO_val(sl.View(respr.OutPkt, 0, len(respr.OutPkt)), respr.EgressID).isValUnsupported // @ decreases func (p *scionPacketProcessor) validateHopExpiry( /*@ ghost ubScionL []byte, ghost ubLL []byte, ghost startLL int, ghost endLL int @*/ ) (respr processResult, reserr error) { expiration := util.SecsToTime(p.infoField.Timestamp). @@ -2264,7 +2264,7 @@ func (p *scionPacketProcessor) validateHopExpiry( /*@ ghost ubScionL []byte, gho /*@ ubScionL, ubLL, startLL, endLL, @*/ ) // @ ghost if tmpErr != nil && tmpRes.OutPkt != nil { - // @ AbsUnsupportedPktIsUnsupportedVal(tmpRes.OutPkt, tmpRes.EgressID) + // @ AbsUnsupportedPktIsUnsupportedVal(sl.View(tmpRes.OutPkt, 0, len(tmpRes.OutPkt)), tmpRes.EgressID) // @ } return tmpRes, tmpErr } @@ -2307,17 +2307,17 @@ func (p *scionPacketProcessor) validateHopExpiry( /*@ ghost ubScionL []byte, gho // @ ensures reserr == nil ==> // @ respr === processResult{} // contracts for IO-spec -// @ requires slayers.ValidPktMetaHdr(ubScionL) && p.scionLayer.EqAbsHeader(ubScionL) -// @ requires absPkt(ubScionL).PathNotFullyTraversed() -// @ requires p.EqAbsHopField(absPkt(ubScionL)) -// @ requires p.EqAbsInfoField(absPkt(ubScionL)) -// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(ubScionL) && p.scionLayer.EqAbsHeader(ubScionL) -// @ ensures reserr == nil ==> absPkt(ubScionL) == old(absPkt(ubScionL)) -// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(ubScionL)) == slayers.IsSupportedPkt(ubScionL) +// @ requires slayers.ValidPktMetaHdr(sl.View(ubScionL, 0, len(ubScionL))) && p.scionLayer.EqAbsHeader(ubScionL) +// @ requires absPkt(sl.View(ubScionL, 0, len(ubScionL))).PathNotFullyTraversed() +// @ requires p.EqAbsHopField(absPkt(sl.View(ubScionL, 0, len(ubScionL)))) +// @ requires p.EqAbsInfoField(absPkt(sl.View(ubScionL, 0, len(ubScionL)))) +// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(sl.View(ubScionL, 0, len(ubScionL))) && p.scionLayer.EqAbsHeader(ubScionL) +// @ ensures reserr == nil ==> absPkt(sl.View(ubScionL, 0, len(ubScionL))) == old(absPkt(sl.View(ubScionL, 0, len(ubScionL)))) +// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(sl.View(ubScionL, 0, len(ubScionL)))) == slayers.IsSupportedPkt(sl.View(ubScionL, 0, len(ubScionL))) // @ ensures reserr == nil ==> -// @ AbsValidateIngressIDConstraint(absPkt(ubScionL), path.ifsToIO_ifs(p.ingressID)) +// @ AbsValidateIngressIDConstraint(absPkt(sl.View(ubScionL, 0, len(ubScionL))), path.ifsToIO_ifs(p.ingressID)) // @ ensures reserr != nil && respr.OutPkt != nil ==> -// @ absIO_val(respr.OutPkt, respr.EgressID).isValUnsupported +// @ absIO_val(sl.View(respr.OutPkt, 0, len(respr.OutPkt)), respr.EgressID).isValUnsupported // @ decreases func (p *scionPacketProcessor) validateIngressID( /*@ ghost ubScionL []byte, ghost ubLL []byte, ghost startLL int, ghost endLL int@*/ ) (respr processResult, reserr error) { pktIngressID := p.hopField.ConsIngress @@ -2336,11 +2336,11 @@ func (p *scionPacketProcessor) validateIngressID( /*@ ghost ubScionL []byte, gho /*@ ubScionL, ubLL, startLL, endLL, @*/ ) // @ ghost if tmpErr != nil && tmpRes.OutPkt != nil { - // @ AbsUnsupportedPktIsUnsupportedVal(tmpRes.OutPkt, tmpRes.EgressID) + // @ AbsUnsupportedPktIsUnsupportedVal(sl.View(tmpRes.OutPkt, 0, len(tmpRes.OutPkt)), tmpRes.EgressID) // @ } return tmpRes, tmpErr } - // @ ghost oldPkt := absPkt(ubScionL) + // @ ghost oldPkt := absPkt(sl.View(ubScionL, 0, len(ubScionL))) // @ reveal p.EqAbsHopField(oldPkt) // @ reveal p.EqAbsInfoField(oldPkt) // @ assert reveal AbsValidateIngressIDConstraint(oldPkt, path.ifsToIO_ifs(p.ingressID)) @@ -2377,16 +2377,16 @@ func (p *scionPacketProcessor) validateIngressID( /*@ ghost ubScionL []byte, gho // @ ensures reserr == nil ==> // @ respr === processResult{} // contracts for IO-spec -// @ requires slayers.ValidPktMetaHdr(ubScionL) && p.scionLayer.EqAbsHeader(ubScionL) -// @ requires absPkt(ubScionL).PathNotFullyTraversed() -// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(ubScionL) && p.scionLayer.EqAbsHeader(ubScionL) +// @ requires slayers.ValidPktMetaHdr(sl.View(ubScionL, 0, len(ubScionL))) && p.scionLayer.EqAbsHeader(ubScionL) +// @ requires absPkt(sl.View(ubScionL, 0, len(ubScionL))).PathNotFullyTraversed() +// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(sl.View(ubScionL, 0, len(ubScionL))) && p.scionLayer.EqAbsHeader(ubScionL) // @ ensures reserr == nil ==> p.DstIsLocalIngressID(ubScionL) // @ ensures reserr == nil ==> p.LastHopLen(ubScionL) -// @ ensures reserr == nil ==> absPkt(ubScionL).PathNotFullyTraversed() -// @ ensures reserr == nil ==> absPkt(ubScionL) == old(absPkt(ubScionL)) -// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(ubScionL)) == slayers.IsSupportedPkt(ubScionL) +// @ ensures reserr == nil ==> absPkt(sl.View(ubScionL, 0, len(ubScionL))).PathNotFullyTraversed() +// @ ensures reserr == nil ==> absPkt(sl.View(ubScionL, 0, len(ubScionL))) == old(absPkt(sl.View(ubScionL, 0, len(ubScionL)))) +// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(sl.View(ubScionL, 0, len(ubScionL)))) == slayers.IsSupportedPkt(sl.View(ubScionL, 0, len(ubScionL))) // @ ensures reserr != nil && respr.OutPkt != nil ==> -// @ absIO_val(respr.OutPkt, respr.EgressID).isValUnsupported +// @ absIO_val(sl.View(respr.OutPkt, 0, len(respr.OutPkt)), respr.EgressID).isValUnsupported // @ decreases func (p *scionPacketProcessor) validateSrcDstIA( /*@ ghost ubScionL []byte, ghost ubLL []byte, ghost startLL int, ghost endLL int @*/ ) (respr processResult, reserr error) { // @ unfold acc(p.scionLayer.Mem(ubScionL), R20) @@ -2396,7 +2396,8 @@ func (p *scionPacketProcessor) validateSrcDstIA( /*@ ghost ubScionL []byte, ghos // @ ghost ubPath := ubScionL[startP:endP] // @ sl.SplitRange_Bytes(ubScionL, startP, endP, R50) // @ p.AbsPktToSubSliceAbsPkt(ubScionL, startP, endP) - // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ubScionL, startP) + // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ubScionL, sl.View(ubScionL, 0, len(ubScionL)), startP) + // @ assert sl.View(ubScionL, 0, len(ubScionL))[:startP] == sl.View(ubScionL, 0, startP) // @ unfold acc(p.scionLayer.HeaderMem(ubScionL[slayers.CmnHdrLen:]), R20) // @ defer fold acc(p.scionLayer.HeaderMem(ubScionL[slayers.CmnHdrLen:]), R20) // @ p.d.getLocalIA() @@ -2422,12 +2423,13 @@ func (p *scionPacketProcessor) validateSrcDstIA( /*@ ghost ubScionL []byte, ghos return p.invalidSrcIA( /*@ ubScionL, ubLL, startLL, endLL @*/ ) } if p.path.IsLastHop( /*@ ubPath @*/ ) != dstIsLocal { - // @ ghost sl.CombineRange_Bytes(ubScionL, startP, endP, R50) + // @ ghost sl.CombineRangeWithViews_Bytes(ubScionL, startP, endP, R50, sl.View(ubScionL, 0, startP), sl.View(ubScionL[startP:endP], 0, (endP)-(startP)), sl.View(ubScionL, endP, len(ubScionL))) return p.invalidDstIA( /*@ ubScionL, ubLL, startLL, endLL @*/ ) } // @ ghost if(p.path.IsLastHopSpec(ubPath)) { // @ p.path.LastHopLemma(ubPath) - // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ubScionL, startP) + // @ assert sl.View(ubScionL, 0, len(ubScionL))[:startP] == sl.View(ubScionL, 0, startP) + // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ubScionL, sl.View(ubScionL, 0, len(ubScionL)), startP) // @ p.SubSliceAbsPktToAbsPkt(ubScionL, startP, endP) // @ } } @@ -2473,7 +2475,7 @@ func (p *scionPacketProcessor) validateSrcDstIA( /*@ ghost ubScionL []byte, ghos // @ respr.OutPkt === p.buffer.UBuf() // @ ensures reserr != nil && reserr.ErrorMem() // @ ensures respr.OutPkt != nil ==> -// @ absIO_val(respr.OutPkt, respr.EgressID).isValUnsupported +// @ absIO_val(sl.View(respr.OutPkt, 0, len(respr.OutPkt)), respr.EgressID).isValUnsupported // @ decreases func (p *scionPacketProcessor) invalidSrcIA( // @ ghost ub []byte, @@ -2490,7 +2492,7 @@ func (p *scionPacketProcessor) invalidSrcIA( /*@ ub , ubLL, startLL, endLL, @*/ ) // @ ghost if tmpErr != nil && tmpRes.OutPkt != nil { - // @ AbsUnsupportedPktIsUnsupportedVal(tmpRes.OutPkt, tmpRes.EgressID) + // @ AbsUnsupportedPktIsUnsupportedVal(sl.View(tmpRes.OutPkt, 0, len(tmpRes.OutPkt)), tmpRes.EgressID) // @ } return tmpRes, tmpErr } @@ -2523,7 +2525,7 @@ func (p *scionPacketProcessor) invalidSrcIA( // @ respr.OutPkt === p.buffer.UBuf() // @ ensures reserr != nil && reserr.ErrorMem() // @ ensures respr.OutPkt != nil ==> -// @ absIO_val(respr.OutPkt, respr.EgressID).isValUnsupported +// @ absIO_val(sl.View(respr.OutPkt, 0, len(respr.OutPkt)), respr.EgressID).isValUnsupported // @ decreases func (p *scionPacketProcessor) invalidDstIA( // @ ghost ub []byte, @@ -2540,7 +2542,7 @@ func (p *scionPacketProcessor) invalidDstIA( /*@ ub , ubLL, startLL, endLL, @*/ ) // @ ghost if tmpErr != nil && tmpRes.OutPkt != nil { - // @ AbsUnsupportedPktIsUnsupportedVal(tmpRes.OutPkt, tmpRes.EgressID) + // @ AbsUnsupportedPktIsUnsupportedVal(sl.View(tmpRes.OutPkt, 0, len(tmpRes.OutPkt)), tmpRes.EgressID) // @ } return tmpRes, tmpErr } @@ -2649,31 +2651,31 @@ func (p *scionPacketProcessor) validateTransitUnderlaySrc( /*@ ghost ub []byte @ // @ requires dp.Valid() // @ requires p.d.WellConfigured() // @ requires p.d.DpAgreesWithSpec(dp) -// @ requires slayers.ValidPktMetaHdr(ubScionL) && p.scionLayer.EqAbsHeader(ubScionL) -// @ requires absPkt(ubScionL).PathNotFullyTraversed() -// @ requires p.EqAbsHopField(absPkt(ubScionL)) -// @ requires p.EqAbsInfoField(absPkt(ubScionL)) +// @ requires slayers.ValidPktMetaHdr(sl.View(ubScionL, 0, len(ubScionL))) && p.scionLayer.EqAbsHeader(ubScionL) +// @ requires absPkt(sl.View(ubScionL, 0, len(ubScionL))).PathNotFullyTraversed() +// @ requires p.EqAbsHopField(absPkt(sl.View(ubScionL, 0, len(ubScionL)))) +// @ requires p.EqAbsInfoField(absPkt(sl.View(ubScionL, 0, len(ubScionL)))) // @ requires p.segmentChange ==> -// @ absPkt(ubScionL).RightSeg != none[io.Seg] && len(get(absPkt(ubScionL).RightSeg).Past) > 0 +// @ absPkt(sl.View(ubScionL, 0, len(ubScionL))).RightSeg != none[io.Seg] && len(get(absPkt(sl.View(ubScionL, 0, len(ubScionL))).RightSeg).Past) > 0 // @ requires !p.segmentChange ==> -// @ AbsValidateIngressIDConstraint(absPkt(ubScionL), path.ifsToIO_ifs(p.ingressID)) +// @ AbsValidateIngressIDConstraint(absPkt(sl.View(ubScionL, 0, len(ubScionL))), path.ifsToIO_ifs(p.ingressID)) // @ requires p.segmentChange ==> -// @ AbsValidateIngressIDConstraintXover(absPkt(ubScionL), path.ifsToIO_ifs(p.ingressID)) -// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(ubScionL) && p.scionLayer.EqAbsHeader(ubScionL) -// @ ensures reserr == nil ==> absPkt(ubScionL) == old(absPkt(ubScionL)) -// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(ubScionL)) == slayers.IsSupportedPkt(ubScionL) -// @ ensures reserr == nil ==> p.NoBouncingPkt(absPkt(ubScionL)) +// @ AbsValidateIngressIDConstraintXover(absPkt(sl.View(ubScionL, 0, len(ubScionL))), path.ifsToIO_ifs(p.ingressID)) +// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(sl.View(ubScionL, 0, len(ubScionL))) && p.scionLayer.EqAbsHeader(ubScionL) +// @ ensures reserr == nil ==> absPkt(sl.View(ubScionL, 0, len(ubScionL))) == old(absPkt(sl.View(ubScionL, 0, len(ubScionL)))) +// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(sl.View(ubScionL, 0, len(ubScionL)))) == slayers.IsSupportedPkt(sl.View(ubScionL, 0, len(ubScionL))) +// @ ensures reserr == nil ==> p.NoBouncingPkt(absPkt(sl.View(ubScionL, 0, len(ubScionL)))) // @ ensures reserr == nil && !p.segmentChange ==> -// @ AbsValidateEgressIDConstraint(absPkt(ubScionL), (p.ingressID != 0), dp) +// @ AbsValidateEgressIDConstraint(absPkt(sl.View(ubScionL, 0, len(ubScionL))), (p.ingressID != 0), dp) // @ ensures reserr == nil && p.segmentChange ==> -// @ absPkt(ubScionL).RightSeg != none[io.Seg] && len(get(absPkt(ubScionL).RightSeg).Past) > 0 +// @ absPkt(sl.View(ubScionL, 0, len(ubScionL))).RightSeg != none[io.Seg] && len(get(absPkt(sl.View(ubScionL, 0, len(ubScionL))).RightSeg).Past) > 0 // @ ensures reserr == nil && p.segmentChange ==> -// @ p.ingressID != 0 && AbsValidateEgressIDConstraintXover(absPkt(ubScionL), dp) +// @ p.ingressID != 0 && AbsValidateEgressIDConstraintXover(absPkt(sl.View(ubScionL, 0, len(ubScionL))), dp) // @ ensures reserr != nil && respr.OutPkt != nil ==> -// @ absIO_val(respr.OutPkt, respr.EgressID).isValUnsupported +// @ absIO_val(sl.View(respr.OutPkt, 0, len(respr.OutPkt)), respr.EgressID).isValUnsupported // @ decreases func (p *scionPacketProcessor) validateEgressID( /*@ ghost dp io.DataPlaneSpec, ghost ubScionL []byte, ghost ubLL []byte, ghost startLL int, ghost endLL int @*/ ) (respr processResult, reserr error) { - // @ ghost oldPkt := absPkt(ubScionL) + // @ ghost oldPkt := absPkt(sl.View(ubScionL, 0, len(ubScionL))) pktEgressID := p.egressInterface( /*@ oldPkt @*/ ) // @ reveal AbsEgressInterfaceConstraint(oldPkt, path.ifsToIO_ifs(pktEgressID)) // @ p.d.getInternalNextHops() @@ -2699,7 +2701,7 @@ func (p *scionPacketProcessor) validateEgressID( /*@ ghost dp io.DataPlaneSpec, /*@ ubScionL, ubLL, startLL, endLL, @*/ ) // @ ghost if tmpErr != nil && tmpRes.OutPkt != nil { - // @ AbsUnsupportedPktIsUnsupportedVal(tmpRes.OutPkt, tmpRes.EgressID) + // @ AbsUnsupportedPktIsUnsupportedVal(sl.View(tmpRes.OutPkt, 0, len(tmpRes.OutPkt)), tmpRes.EgressID) // @ } return tmpRes, tmpErr } @@ -2739,7 +2741,7 @@ func (p *scionPacketProcessor) validateEgressID( /*@ ghost dp io.DataPlaneSpec, "egress_id", pktEgressID, "egress_type", egress), /*@ ubScionL, ubLL, startLL, endLL, @*/) // @ ghost if tmpErr != nil && tmpRes.OutPkt != nil { - // @ AbsUnsupportedPktIsUnsupportedVal(tmpRes.OutPkt, tmpRes.EgressID) + // @ AbsUnsupportedPktIsUnsupportedVal(sl.View(tmpRes.OutPkt, 0, len(tmpRes.OutPkt)), tmpRes.EgressID) // @ } return tmpRes, tmpErr } @@ -2770,7 +2772,7 @@ func (p *scionPacketProcessor) validateEgressID( /*@ ghost dp io.DataPlaneSpec, "egress_id", pktEgressID, "egress_type", egress), /*@ ubScionL, ubLL, startLL, endLL, @*/) // @ ghost if tmpErr != nil && tmpRes.OutPkt != nil { - // @ AbsUnsupportedPktIsUnsupportedVal(tmpRes.OutPkt, tmpRes.EgressID) + // @ AbsUnsupportedPktIsUnsupportedVal(sl.View(tmpRes.OutPkt, 0, len(tmpRes.OutPkt)), tmpRes.EgressID) // @ } return tmpRes, tmpErr } @@ -2784,12 +2786,12 @@ func (p *scionPacketProcessor) validateEgressID( /*@ ghost dp io.DataPlaneSpec, // @ requires sl.Bytes(ub, 0, len(ub)) // @ requires acc(&p.ingressID, R21) // preconditions for IO: -// @ requires slayers.ValidPktMetaHdr(ub) && p.scionLayer.EqAbsHeader(ub) -// @ requires absPkt(ub).PathNotFullyTraversed() +// @ requires slayers.ValidPktMetaHdr(sl.View(ub, 0, len(ub))) && p.scionLayer.EqAbsHeader(ub) +// @ requires absPkt(sl.View(ub, 0, len(ub))).PathNotFullyTraversed() // @ requires acc(&p.d, R55) && acc(p.d.Mem(), _) && acc(&p.ingressID, R55) // @ requires p.LastHopLen(ub) -// @ requires p.EqAbsHopField(absPkt(ub)) -// @ requires p.EqAbsInfoField(absPkt(ub)) +// @ requires p.EqAbsHopField(absPkt(sl.View(ub, 0, len(ub)))) +// @ requires p.EqAbsInfoField(absPkt(sl.View(ub, 0, len(ub)))) // @ ensures acc(&p.ingressID, R21) // @ ensures acc(&p.hopField, R20) // @ ensures sl.Bytes(ub, 0, len(ub)) @@ -2799,14 +2801,14 @@ func (p *scionPacketProcessor) validateEgressID( /*@ ghost dp io.DataPlaneSpec, // @ ensures err != nil ==> err.ErrorMem() // posconditions for IO: // @ ensures acc(&p.d, R55) && acc(p.d.Mem(), _) && acc(&p.ingressID, R55) -// @ ensures err == nil ==> slayers.ValidPktMetaHdr(ub) && p.scionLayer.EqAbsHeader(ub) -// @ ensures err == nil ==> absPkt(ub).PathNotFullyTraversed() +// @ ensures err == nil ==> slayers.ValidPktMetaHdr(sl.View(ub, 0, len(ub))) && p.scionLayer.EqAbsHeader(ub) +// @ ensures err == nil ==> absPkt(sl.View(ub, 0, len(ub))).PathNotFullyTraversed() // @ ensures err == nil ==> -// @ absPkt(ub) == AbsUpdateNonConsDirIngressSegID(old(absPkt(ub)), path.ifsToIO_ifs(p.ingressID)) +// @ absPkt(sl.View(ub, 0, len(ub))) == AbsUpdateNonConsDirIngressSegID(old(absPkt(sl.View(ub, 0, len(ub)))), path.ifsToIO_ifs(p.ingressID)) // @ ensures err == nil ==> p.LastHopLen(ub) -// @ ensures err == nil ==> p.EqAbsHopField(absPkt(ub)) -// @ ensures err == nil ==> p.EqAbsInfoField(absPkt(ub)) -// @ ensures err == nil ==> old(slayers.IsSupportedPkt(ub)) == slayers.IsSupportedPkt(ub) +// @ ensures err == nil ==> p.EqAbsHopField(absPkt(sl.View(ub, 0, len(ub)))) +// @ ensures err == nil ==> p.EqAbsInfoField(absPkt(sl.View(ub, 0, len(ub)))) +// @ ensures err == nil ==> old(slayers.IsSupportedPkt(sl.View(ub, 0, len(ub)))) == slayers.IsSupportedPkt(sl.View(ub, 0, len(ub))) // @ decreases func (p *scionPacketProcessor) updateNonConsDirIngressSegID( /*@ ghost ub []byte @*/ ) (err error) { // @ ghost ubPath := p.scionLayer.UBPath(ub) @@ -2820,8 +2822,8 @@ func (p *scionPacketProcessor) updateNonConsDirIngressSegID( /*@ ghost ub []byte // means this comes from this AS itself, so nothing has to be done. // TODO(lukedirtwalker): For packets destined to peer links this shouldn't // be updated. - // @ reveal p.EqAbsInfoField(absPkt(ub)) - // @ reveal p.EqAbsHopField(absPkt(ub)) + // @ reveal p.EqAbsInfoField(absPkt(sl.View(ub, 0, len(ub)))) + // @ reveal p.EqAbsHopField(absPkt(sl.View(ub, 0, len(ub)))) if !p.infoField.ConsDir && p.ingressID != 0 { p.infoField.UpdateSegID(p.hopField.Mac /*@, p.hopField.Abs() @*/) // @ reveal p.LastHopLen(ub) @@ -2832,31 +2834,42 @@ func (p *scionPacketProcessor) updateNonConsDirIngressSegID( /*@ ghost ub []byte // @ sl.SplitRange_Bytes(ub, start, end, HalfPerm) // @ sl.SplitByIndex_Bytes(ub, 0, start, slayers.CmnHdrLen, R54) // @ sl.Reslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) - // @ slayers.IsSupportedPktSubslice(ub, slayers.CmnHdrLen) + // @ slayers.IsSupportedPktSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) + // the view of the left piece is pinned across the modification of + // the path slice; the prefix asserts carry the common-header bytes, + // and with them IsSupportedPkt, from the state before to the state after + // @ ghost vHdrPre := sl.View(ub, 0, start) + // @ assert sl.View(ub, 0, len(ub))[:start] == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:slayers.CmnHdrLen] == vHdrPre[:slayers.CmnHdrLen] // @ p.AbsPktToSubSliceAbsPkt(ub, start, end) - // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ub, start) + // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ub, sl.View(ub, 0, len(ub)), start) + // @ assert sl.View(ub, 0, len(ub))[:start] == sl.View(ub, 0, start) // @ sl.SplitRange_Bytes(ub, start, end, HalfPerm) if err := p.path.SetInfoField(p.infoField, int( /*@ unfolding acc(p.path.Mem(ubPath), R45) in (unfolding acc(p.path.Base.Mem(), R50) in @*/ p.path.PathMeta.CurrINF) /*@ ) , ubPath, @*/); err != nil { // @ sl.Unslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) // @ sl.CombineAtIndex_Bytes(ub, 0, start, slayers.CmnHdrLen, R54) - // @ ghost sl.CombineRange_Bytes(ub, start, end, writePerm) + // @ ghost sl.CombineRangeWithViews_Bytes(ub, start, end, writePerm, sl.View(ub, 0, start), sl.View(ub[start:end], 0, (end)-(start)), sl.View(ub, end, len(ub))) return serrors.WrapStr("update info field", err) } - // @ ghost sl.CombineRange_Bytes(ub, start, end, HalfPerm) - // @ slayers.IsSupportedPktSubslice(ub, slayers.CmnHdrLen) + // @ ghost sl.CombineRangeWithViews_Bytes(ub, start, end, HalfPerm, sl.View(ub, 0, start), sl.View(ub[start:end], 0, (end)-(start)), sl.View(ub, end, len(ub))) + // @ assert sl.View(ub, 0, start) == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:start] == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:slayers.CmnHdrLen] == vHdrPre[:slayers.CmnHdrLen] + // @ slayers.IsSupportedPktSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) // @ sl.Unslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) // @ sl.CombineAtIndex_Bytes(ub, 0, start, slayers.CmnHdrLen, R54) - // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ub, start) + // @ assert sl.View(ub, 0, len(ub))[:start] == sl.View(ub, 0, start) + // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ub, sl.View(ub, 0, len(ub)), start) // @ p.SubSliceAbsPktToAbsPkt(ub, start, end) - // @ ghost sl.CombineRange_Bytes(ub, start, end, HalfPerm) - // @ absPktFutureLemma(ub) - // @ assert absPkt(ub).CurrSeg.UInfo == + // @ ghost sl.CombineRangeWithViews_Bytes(ub, start, end, HalfPerm, sl.View(ub, 0, start), sl.View(ub[start:end], 0, (end)-(start)), sl.View(ub, end, len(ub))) + // @ absPktFutureLemma(sl.View(ub, 0, len(ub))) + // @ assert absPkt(sl.View(ub, 0, len(ub))).CurrSeg.UInfo == // @ old(io.upd_uinfo(path.AbsUInfoFromUint16(p.infoField.SegID), p.hopField.Abs())) - // @ assert reveal p.EqAbsInfoField(absPkt(ub)) - // @ assert reveal p.EqAbsHopField(absPkt(ub)) + // @ assert reveal p.EqAbsInfoField(absPkt(sl.View(ub, 0, len(ub)))) + // @ assert reveal p.EqAbsHopField(absPkt(sl.View(ub, 0, len(ub)))) // @ assert reveal p.LastHopLen(ub) } - // @ assert absPkt(ub) == reveal AbsUpdateNonConsDirIngressSegID(old(absPkt(ub)), path.ifsToIO_ifs(p.ingressID)) + // @ assert absPkt(sl.View(ub, 0, len(ub))) == reveal AbsUpdateNonConsDirIngressSegID(old(absPkt(sl.View(ub, 0, len(ub)))), path.ifsToIO_ifs(p.ingressID)) return nil } @@ -2933,22 +2946,22 @@ func (p *scionPacketProcessor) currentHopPointer( /*@ ghost ubScionL []byte @*/ // @ ensures reserr == nil ==> // @ respr === processResult{} // contracts for IO-spec -// @ requires slayers.ValidPktMetaHdr(ubScionL) && p.scionLayer.EqAbsHeader(ubScionL) -// @ requires absPkt(ubScionL).PathNotFullyTraversed() -// @ requires p.EqAbsHopField(absPkt(ubScionL)) -// @ requires p.EqAbsInfoField(absPkt(ubScionL)) -// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(ubScionL) && p.scionLayer.EqAbsHeader(ubScionL) -// @ ensures reserr == nil ==> absPkt(ubScionL).PathNotFullyTraversed() -// @ ensures reserr == nil ==> AbsVerifyCurrentMACConstraint(absPkt(ubScionL), dp) -// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(ubScionL)) == slayers.IsSupportedPkt(ubScionL) -// @ ensures reserr == nil ==> absPkt(ubScionL) == old(absPkt(ubScionL)) +// @ requires slayers.ValidPktMetaHdr(sl.View(ubScionL, 0, len(ubScionL))) && p.scionLayer.EqAbsHeader(ubScionL) +// @ requires absPkt(sl.View(ubScionL, 0, len(ubScionL))).PathNotFullyTraversed() +// @ requires p.EqAbsHopField(absPkt(sl.View(ubScionL, 0, len(ubScionL)))) +// @ requires p.EqAbsInfoField(absPkt(sl.View(ubScionL, 0, len(ubScionL)))) +// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(sl.View(ubScionL, 0, len(ubScionL))) && p.scionLayer.EqAbsHeader(ubScionL) +// @ ensures reserr == nil ==> absPkt(sl.View(ubScionL, 0, len(ubScionL))).PathNotFullyTraversed() +// @ ensures reserr == nil ==> AbsVerifyCurrentMACConstraint(absPkt(sl.View(ubScionL, 0, len(ubScionL))), dp) +// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(sl.View(ubScionL, 0, len(ubScionL)))) == slayers.IsSupportedPkt(sl.View(ubScionL, 0, len(ubScionL))) +// @ ensures reserr == nil ==> absPkt(sl.View(ubScionL, 0, len(ubScionL))) == old(absPkt(sl.View(ubScionL, 0, len(ubScionL)))) // @ ensures reserr == nil ==> p.DstIsLocalIngressID(ubScionL) == old(p.DstIsLocalIngressID(ubScionL)) // @ ensures reserr == nil ==> p.LastHopLen(ubScionL) == old(p.LastHopLen(ubScionL)) // @ ensures reserr != nil && respr.OutPkt != nil ==> -// @ absIO_val(respr.OutPkt, respr.EgressID).isValUnsupported +// @ absIO_val(sl.View(respr.OutPkt, 0, len(respr.OutPkt)), respr.EgressID).isValUnsupported // @ decreases func (p *scionPacketProcessor) verifyCurrentMAC( /*@ ghost dp io.DataPlaneSpec, ghost ubScionL []byte, ghost ubLL []byte, ghost startLL int, ghost endLL int @*/ ) (respr processResult, reserr error) { - // @ ghost oldPkt := absPkt(ubScionL) + // @ ghost oldPkt := absPkt(sl.View(ubScionL, 0, len(ubScionL))) fullMac := path.FullMAC(p.mac, p.infoField, p.hopField, p.macBuffers.scionInput) // @ fold acc(sl.Bytes(p.hopField.Mac[:path.MacLen], 0, path.MacLen), R21) // @ defer unfold acc(sl.Bytes(p.hopField.Mac[:path.MacLen], 0, path.MacLen), R21) @@ -2980,7 +2993,7 @@ func (p *scionPacketProcessor) verifyCurrentMAC( /*@ ghost dp io.DataPlaneSpec, /*@ ubScionL, ubLL, startLL, endLL, @*/ ) // @ ghost if tmpErr != nil && tmpRes.OutPkt != nil { - // @ AbsUnsupportedPktIsUnsupportedVal(tmpRes.OutPkt, tmpRes.EgressID) + // @ AbsUnsupportedPktIsUnsupportedVal(sl.View(tmpRes.OutPkt, 0, len(tmpRes.OutPkt)), tmpRes.EgressID) // @ } return tmpRes, tmpErr } @@ -3008,8 +3021,8 @@ func (p *scionPacketProcessor) verifyCurrentMAC( /*@ ghost dp io.DataPlaneSpec, // @ requires sl.Bytes(p.buffer.UBuf(), 0, len(p.buffer.UBuf())) // @ requires acc(&p.d, R15) && acc(p.d.Mem(), _) // pres for IO: -// @ requires slayers.ValidPktMetaHdr(ubScionL) && p.scionLayer.EqAbsHeader(ubScionL) -// @ requires absPkt(ubScionL).PathNotFullyTraversed() +// @ requires slayers.ValidPktMetaHdr(sl.View(ubScionL, 0, len(ubScionL))) && p.scionLayer.EqAbsHeader(ubScionL) +// @ requires absPkt(sl.View(ubScionL, 0, len(ubScionL))).PathNotFullyTraversed() // @ preserves acc(&p.ingressID, R40) // @ preserves ubLL == nil || ubLL === ubScionL[startLL:endLL] // @ preserves acc(&p.lastLayer, R55) && p.lastLayer != nil @@ -3037,12 +3050,12 @@ func (p *scionPacketProcessor) verifyCurrentMAC( /*@ ghost dp io.DataPlaneSpec, // @ ensures reserr == nil ==> // @ respr === processResult{} // posts for IO: -// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(ubScionL) && p.scionLayer.EqAbsHeader(ubScionL) -// @ ensures reserr == nil ==> absPkt(ubScionL).PathNotFullyTraversed() -// @ ensures reserr == nil ==> absPkt(ubScionL) == old(absPkt(ubScionL)) -// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(ubScionL)) == slayers.IsSupportedPkt(ubScionL) +// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(sl.View(ubScionL, 0, len(ubScionL))) && p.scionLayer.EqAbsHeader(ubScionL) +// @ ensures reserr == nil ==> absPkt(sl.View(ubScionL, 0, len(ubScionL))).PathNotFullyTraversed() +// @ ensures reserr == nil ==> absPkt(sl.View(ubScionL, 0, len(ubScionL))) == old(absPkt(sl.View(ubScionL, 0, len(ubScionL)))) +// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(sl.View(ubScionL, 0, len(ubScionL)))) == slayers.IsSupportedPkt(sl.View(ubScionL, 0, len(ubScionL))) // @ ensures reserr != nil && respr.OutPkt != nil ==> -// @ absIO_val(respr.OutPkt, respr.EgressID).isValUnsupported +// @ absIO_val(sl.View(respr.OutPkt, 0, len(respr.OutPkt)), respr.EgressID).isValUnsupported // @ decreases 0 if sync.IgnoreBlockingForTermination() func (p *scionPacketProcessor) resolveInbound( /*@ ghost ubScionL []byte, ghost ubLL []byte, ghost startLL int, ghost endLL int @*/ ) (resaddr *net.UDPAddr, respr processResult, reserr error /*@ , ghost addrAliasesUb bool @*/) { // (VerifiedSCION) the parameter used to be p.scionLayer, @@ -3061,7 +3074,7 @@ func (p *scionPacketProcessor) resolveInbound( /*@ ghost ubScionL []byte, ghost err, /*@ ubScionL, ubLL, startLL, endLL, @*/) // @ ghost if err != nil && r.OutPkt != nil { - // @ AbsUnsupportedPktIsUnsupportedVal(r.OutPkt, r.EgressID) + // @ AbsUnsupportedPktIsUnsupportedVal(sl.View(r.OutPkt, 0, len(r.OutPkt)), r.EgressID) // @ } return nil, r, err /*@ , false @*/ default: @@ -3078,10 +3091,10 @@ func (p *scionPacketProcessor) resolveInbound( /*@ ghost ubScionL []byte, ghost // @ requires acc(&p.hopField, R20) // @ requires !p.GetIsXoverSpec(ub) // Preconditions for IO: -// @ requires slayers.ValidPktMetaHdr(ub) && p.scionLayer.EqAbsHeader(ub) -// @ requires absPkt(ub).PathNotFullyTraversed() -// @ requires p.EqAbsHopField(absPkt(ub)) -// @ requires p.EqAbsInfoField(absPkt(ub)) +// @ requires slayers.ValidPktMetaHdr(sl.View(ub, 0, len(ub))) && p.scionLayer.EqAbsHeader(ub) +// @ requires absPkt(sl.View(ub, 0, len(ub))).PathNotFullyTraversed() +// @ requires p.EqAbsHopField(absPkt(sl.View(ub, 0, len(ub)))) +// @ requires p.EqAbsInfoField(absPkt(sl.View(ub, 0, len(ub)))) // @ ensures acc(&p.infoField) // @ ensures acc(&p.hopField, R20) // @ ensures sl.Bytes(ub, 0, len(ub)) @@ -3090,10 +3103,10 @@ func (p *scionPacketProcessor) resolveInbound( /*@ ghost ubScionL []byte, ghost // @ ensures reserr != nil ==> p.scionLayer.NonInitMem() // @ ensures reserr != nil ==> reserr.ErrorMem() // Postconditions for IO: -// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(ub) && p.scionLayer.EqAbsHeader(ub) -// @ ensures reserr == nil ==> len(absPkt(ub).CurrSeg.Future) >= 0 -// @ ensures reserr == nil ==> absPkt(ub) == AbsProcessEgress(old(absPkt(ub))) -// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(ub)) == slayers.IsSupportedPkt(ub) +// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(sl.View(ub, 0, len(ub))) && p.scionLayer.EqAbsHeader(ub) +// @ ensures reserr == nil ==> len(absPkt(sl.View(ub, 0, len(ub))).CurrSeg.Future) >= 0 +// @ ensures reserr == nil ==> absPkt(sl.View(ub, 0, len(ub))) == AbsProcessEgress(old(absPkt(sl.View(ub, 0, len(ub))))) +// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(sl.View(ub, 0, len(ub)))) == slayers.IsSupportedPkt(sl.View(ub, 0, len(ub))) // @ decreases func (p *scionPacketProcessor) processEgress( /*@ ghost ub []byte @*/ ) (reserr error) { // @ ghost ubPath := p.scionLayer.UBPath(ub) @@ -3105,13 +3118,20 @@ func (p *scionPacketProcessor) processEgress( /*@ ghost ub []byte @*/ ) (reserr // @ sl.SplitRange_Bytes(ub, startP, endP, HalfPerm) // @ sl.SplitByIndex_Bytes(ub, 0, startP, slayers.CmnHdrLen, R54) // @ sl.Reslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) - // @ slayers.IsSupportedPktSubslice(ub, slayers.CmnHdrLen) + // @ slayers.IsSupportedPktSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) + // the view of the left piece is pinned across the modification of + // the path slice; the prefix asserts carry the common-header bytes, + // and with them IsSupportedPkt, from the state before to the state after + // @ ghost vHdrPre := sl.View(ub, 0, startP) + // @ assert sl.View(ub, 0, len(ub))[:startP] == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:slayers.CmnHdrLen] == vHdrPre[:slayers.CmnHdrLen] // @ p.AbsPktToSubSliceAbsPkt(ub, startP, endP) - // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ub, startP) - // @ reveal p.EqAbsInfoField(absPkt(ub)) - // @ reveal p.EqAbsHopField(absPkt(ub)) + // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ub, sl.View(ub, 0, len(ub)), startP) + // @ assert sl.View(ub, 0, len(ub))[:startP] == sl.View(ub, 0, startP) + // @ reveal p.EqAbsInfoField(absPkt(sl.View(ub, 0, len(ub)))) + // @ reveal p.EqAbsHopField(absPkt(sl.View(ub, 0, len(ub)))) // @ sl.SplitRange_Bytes(ub, startP, endP, HalfPerm) - // @ reveal p.scionLayer.ValidHeaderOffset(ub, startP) + // @ reveal p.scionLayer.ValidHeaderOffset(ub, sl.View(ub, 0, startP)) // @ unfold acc(p.scionLayer.Mem(ub), R55) // we are the egress router and if we go in construction direction we // need to update the SegID. @@ -3143,16 +3163,20 @@ func (p *scionPacketProcessor) processEgress( /*@ ghost ub []byte @*/ ) (reserr return serrors.WrapStr("incrementing path", err) } // @ fold acc(p.scionLayer.Mem(ub), R55) - // @ assert reveal p.scionLayer.ValidHeaderOffset(ub, startP) - // @ ghost sl.CombineRange_Bytes(ub, startP, endP, HalfPerm) - // @ slayers.IsSupportedPktSubslice(ub, slayers.CmnHdrLen) + // @ assert reveal p.scionLayer.ValidHeaderOffset(ub, sl.View(ub, 0, startP)) + // @ ghost sl.CombineRangeWithViews_Bytes(ub, startP, endP, HalfPerm, sl.View(ub, 0, startP), sl.View(ub[startP:endP], 0, (endP)-(startP)), sl.View(ub, endP, len(ub))) + // @ assert sl.View(ub, 0, startP) == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:startP] == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:slayers.CmnHdrLen] == vHdrPre[:slayers.CmnHdrLen] + // @ slayers.IsSupportedPktSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) // @ sl.Unslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) // @ sl.CombineAtIndex_Bytes(ub, 0, startP, slayers.CmnHdrLen, R54) - // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ub, startP) + // @ assert sl.View(ub, 0, len(ub))[:startP] == sl.View(ub, 0, startP) + // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ub, sl.View(ub, 0, len(ub)), startP) // @ p.SubSliceAbsPktToAbsPkt(ub, startP, endP) - // @ ghost sl.CombineRange_Bytes(ub, startP, endP, HalfPerm) - // @ absPktFutureLemma(ub) - // @ assert absPkt(ub) == reveal AbsProcessEgress(old(absPkt(ub))) + // @ ghost sl.CombineRangeWithViews_Bytes(ub, startP, endP, HalfPerm, sl.View(ub, 0, startP), sl.View(ub[startP:endP], 0, (endP)-(startP)), sl.View(ub, endP, len(ub))) + // @ absPktFutureLemma(sl.View(ub, 0, len(ub))) + // @ assert absPkt(sl.View(ub, 0, len(ub))) == reveal AbsProcessEgress(old(absPkt(sl.View(ub, 0, len(ub))))) // @ fold acc(p.scionLayer.Mem(ub), 1-R55) return nil } @@ -3165,7 +3189,7 @@ func (p *scionPacketProcessor) processEgress( /*@ ghost ub []byte @*/ ) (reserr // @ requires acc(&p.hopField) // @ requires acc(&p.infoField) // Preconditions for IO: -// @ requires slayers.ValidPktMetaHdr(ub) && p.scionLayer.EqAbsHeader(ub) +// @ requires slayers.ValidPktMetaHdr(sl.View(ub, 0, len(ub))) && p.scionLayer.EqAbsHeader(ub) // @ requires p.GetIsXoverSpec(ub) // @ requires let ubPath := p.scionLayer.UBPath(ub) in // @ (unfolding acc(p.scionLayer.Mem(ub), _) in p.path.GetBase(ubPath)) == currBase @@ -3183,17 +3207,17 @@ func (p *scionPacketProcessor) processEgress( /*@ ghost ub []byte @*/ ) (reserr // @ ensures respr === processResult{} // @ ensures reserr != nil ==> reserr.ErrorMem() // Postconditions for IO: -// @ ensures reserr == nil ==> len(old(absPkt(ub)).CurrSeg.Future) == 1 -// @ ensures reserr == nil ==> old(absPkt(ub)).LeftSeg != none[io.Seg] -// @ ensures reserr == nil ==> len(get(old(absPkt(ub)).LeftSeg).Future) > 0 -// @ ensures reserr == nil ==> len(get(old(absPkt(ub)).LeftSeg).History) == 0 -// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(ub) && p.scionLayer.EqAbsHeader(ub) -// @ ensures reserr == nil ==> absPkt(ub).PathNotFullyTraversed() -// @ ensures reserr == nil ==> p.EqAbsHopField(absPkt(ub)) -// @ ensures reserr == nil ==> p.EqAbsInfoField(absPkt(ub)) -// @ ensures reserr == nil ==> absPkt(ub) == AbsDoXover(old(absPkt(ub))) +// @ ensures reserr == nil ==> len(old(absPkt(sl.View(ub, 0, len(ub)))).CurrSeg.Future) == 1 +// @ ensures reserr == nil ==> old(absPkt(sl.View(ub, 0, len(ub)))).LeftSeg != none[io.Seg] +// @ ensures reserr == nil ==> len(get(old(absPkt(sl.View(ub, 0, len(ub)))).LeftSeg).Future) > 0 +// @ ensures reserr == nil ==> len(get(old(absPkt(sl.View(ub, 0, len(ub)))).LeftSeg).History) == 0 +// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(sl.View(ub, 0, len(ub))) && p.scionLayer.EqAbsHeader(ub) +// @ ensures reserr == nil ==> absPkt(sl.View(ub, 0, len(ub))).PathNotFullyTraversed() +// @ ensures reserr == nil ==> p.EqAbsHopField(absPkt(sl.View(ub, 0, len(ub)))) +// @ ensures reserr == nil ==> p.EqAbsInfoField(absPkt(sl.View(ub, 0, len(ub)))) +// @ ensures reserr == nil ==> absPkt(sl.View(ub, 0, len(ub))) == AbsDoXover(old(absPkt(sl.View(ub, 0, len(ub))))) // @ ensures reserr == nil ==> -// @ old(slayers.IsSupportedPkt(ub)) == slayers.IsSupportedPkt(ub) +// @ old(slayers.IsSupportedPkt(sl.View(ub, 0, len(ub)))) == slayers.IsSupportedPkt(sl.View(ub, 0, len(ub))) // @ ensures reserr == nil ==> // @ let ubPath := p.scionLayer.UBPath(ub) in // @ (unfolding acc(p.scionLayer.Mem(ub), _) in @@ -3213,17 +3237,24 @@ func (p *scionPacketProcessor) doXover( /*@ ghost ub []byte, ghost currBase scio // @ sl.SplitRange_Bytes(ub, startP, endP, HalfPerm) // @ sl.SplitByIndex_Bytes(ub, 0, startP, slayers.CmnHdrLen, R54) // @ sl.Reslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) - // @ slayers.IsSupportedPktSubslice(ub, slayers.CmnHdrLen) + // @ slayers.IsSupportedPktSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) + // the view of the left piece is pinned across the modification of + // the path slice; the prefix asserts carry the common-header bytes, + // and with them IsSupportedPkt, from the state before to the state after + // @ ghost vHdrPre := sl.View(ub, 0, startP) + // @ assert sl.View(ub, 0, len(ub))[:startP] == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:slayers.CmnHdrLen] == vHdrPre[:slayers.CmnHdrLen] // @ assert p.path == p.scionLayer.GetPath(ub) // @ p.AbsPktToSubSliceAbsPkt(ub, startP, endP) // @ assert p.path == p.scionLayer.GetPath(ub) - // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ub, startP) - // @ ghost preAbsPkt := p.path.absPkt(ubPath) + // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ub, sl.View(ub, 0, len(ub)), startP) + // @ assert sl.View(ub, 0, len(ub))[:startP] == sl.View(ub, 0, startP) + // @ ghost preAbsPkt := p.path.absPkt(sl.View(ubPath, 0, len(ubPath))) // @ p.path.XoverLemma(ubPath) - // @ reveal p.EqAbsInfoField(absPkt(ub)) - // @ reveal p.EqAbsHopField(absPkt(ub)) + // @ reveal p.EqAbsInfoField(absPkt(sl.View(ub, 0, len(ub)))) + // @ reveal p.EqAbsHopField(absPkt(sl.View(ub, 0, len(ub)))) // @ sl.SplitRange_Bytes(ub, startP, endP, HalfPerm) - // @ reveal p.scionLayer.ValidHeaderOffset(ub, startP) + // @ reveal p.scionLayer.ValidHeaderOffset(ub, sl.View(ub, 0, startP)) // @ unfold acc(p.scionLayer.Mem(ub), R55) // @ assert p.path.GetBase(ubPath) == currBase // @ ghost nextBase := currBase.IncPathSpec() @@ -3239,25 +3270,29 @@ func (p *scionPacketProcessor) doXover( /*@ ghost ub []byte, ghost currBase scio return processResult{}, serrors.WrapStr("incrementing path", err) } // @ assert p.path.GetBase(ubPath) == nextBase - // @ assert p.path.absPkt(ubPath) == scion.AbsXover(preAbsPkt) + // @ assert p.path.absPkt(sl.View(ubPath, 0, len(ubPath))) == scion.AbsXover(preAbsPkt) // @ fold acc(p.scionLayer.Mem(ub), R55) - // @ assert reveal p.scionLayer.ValidHeaderOffset(ub, startP) - // @ ghost sl.CombineRange_Bytes(ub, startP, endP, HalfPerm) - // @ slayers.IsSupportedPktSubslice(ub, slayers.CmnHdrLen) + // @ assert reveal p.scionLayer.ValidHeaderOffset(ub, sl.View(ub, 0, startP)) + // @ ghost sl.CombineRangeWithViews_Bytes(ub, startP, endP, HalfPerm, sl.View(ub, 0, startP), sl.View(ub[startP:endP], 0, (endP)-(startP)), sl.View(ub, endP, len(ub))) + // @ assert sl.View(ub, 0, startP) == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:startP] == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:slayers.CmnHdrLen] == vHdrPre[:slayers.CmnHdrLen] + // @ slayers.IsSupportedPktSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) // @ sl.Unslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) // @ sl.CombineAtIndex_Bytes(ub, 0, startP, slayers.CmnHdrLen, R54) // @ assert p.path == p.scionLayer.GetPath(ub) - // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ub, startP) - // @ assert p.scionLayer.ValidHeaderOffset(ub, len(ub)) + // @ assert sl.View(ub, 0, len(ub))[:startP] == sl.View(ub, 0, startP) + // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ub, sl.View(ub, 0, len(ub)), startP) + // @ assert p.scionLayer.ValidHeaderOffset(ub, sl.View(ub, 0, len(ub))) // @ assert p.path == p.scionLayer.GetPath(ub) // @ p.SubSliceAbsPktToAbsPkt(ub, startP, endP) - // @ assert p.scionLayer.ValidHeaderOffset(ub, len(ub)) + // @ assert p.scionLayer.ValidHeaderOffset(ub, sl.View(ub, 0, len(ub))) // @ assert p.path == p.scionLayer.GetPath(ub) // @ assert p.path.GetBase(ubPath) == nextBase - // @ assert len(get(old(absPkt(ub)).LeftSeg).Future) > 0 - // @ assert len(get(old(absPkt(ub)).LeftSeg).History) == 0 - // @ assert slayers.ValidPktMetaHdr(ub) && p.scionLayer.EqAbsHeader(ub) - // @ assert absPkt(ub) == reveal AbsDoXover(old(absPkt(ub))) + // @ assert len(get(old(absPkt(sl.View(ub, 0, len(ub)))).LeftSeg).Future) > 0 + // @ assert len(get(old(absPkt(sl.View(ub, 0, len(ub)))).LeftSeg).History) == 0 + // @ assert slayers.ValidPktMetaHdr(sl.View(ub, 0, len(ub))) && p.scionLayer.EqAbsHeader(ub) + // @ assert absPkt(sl.View(ub, 0, len(ub))) == reveal AbsDoXover(old(absPkt(sl.View(ub, 0, len(ub))))) // @ assert p.path == p.scionLayer.GetPath(ub) // @ assert p.path.GetBase(ubPath) == nextBase var err error @@ -3286,13 +3321,13 @@ func (p *scionPacketProcessor) doXover( /*@ ghost ub []byte, ghost currBase scio } // @ assert p.path.GetBase(ubPath) == nextBase // @ p.SubSliceAbsPktToAbsPkt(ub, startP, endP) - // @ ghost sl.CombineRange_Bytes(ub, startP, endP, HalfPerm/2) - // @ absPktFutureLemma(ub) + // @ ghost sl.CombineRangeWithViews_Bytes(ub, startP, endP, HalfPerm/2, sl.View(ub, 0, startP), sl.View(ub[startP:endP], 0, (endP)-(startP)), sl.View(ub, endP, len(ub))) + // @ absPktFutureLemma(sl.View(ub, 0, len(ub))) // @ p.path.DecodingLemma(ubPath, p.infoField, p.hopField) - // @ assert reveal p.path.EqAbsInfoField(p.path.absPkt(ubPath), p.infoField.ToAbsInfoField()) - // @ assert reveal p.path.EqAbsHopField(p.path.absPkt(ubPath), p.hopField.Abs()) - // @ assert reveal p.EqAbsHopField(absPkt(ub)) - // @ assert reveal p.EqAbsInfoField(absPkt(ub)) + // @ assert reveal p.path.EqAbsInfoField(p.path.absPkt(sl.View(ubPath, 0, len(ubPath))), p.infoField.ToAbsInfoField()) + // @ assert reveal p.path.EqAbsHopField(p.path.absPkt(sl.View(ubPath, 0, len(ubPath))), p.hopField.Abs()) + // @ assert reveal p.EqAbsHopField(absPkt(sl.View(ub, 0, len(ub)))) + // @ assert reveal p.EqAbsInfoField(absPkt(sl.View(ub, 0, len(ub)))) // @ ghost sl.CombineRange_Bytes(ub, startP, endP, HalfPerm/2) // @ fold acc(p.scionLayer.Mem(ub), 1-R55) // @ assert currBase.IncPathSpec().Valid() @@ -3366,10 +3401,10 @@ func (p *scionPacketProcessor) egressInterface( /*@ ghost oldPkt io.Pkt @*/ ) (e // @ requires acc(&p.hopField, R20) // @ requires acc(&p.ingressID, R21) // pres for IO: -// @ requires slayers.ValidPktMetaHdr(ub) && p.scionLayer.EqAbsHeader(ub) -// @ requires absPkt(ub).PathNotFullyTraversed() -// @ requires p.EqAbsInfoField(absPkt(ub)) -// @ requires p.EqAbsHopField(absPkt(ub)) +// @ requires slayers.ValidPktMetaHdr(sl.View(ub, 0, len(ub))) && p.scionLayer.EqAbsHeader(ub) +// @ requires absPkt(sl.View(ub, 0, len(ub))).PathNotFullyTraversed() +// @ requires p.EqAbsInfoField(absPkt(sl.View(ub, 0, len(ub)))) +// @ requires p.EqAbsHopField(absPkt(sl.View(ub, 0, len(ub)))) // @ preserves ubLL == nil || ubLL === ub[startLL:endLL] // @ preserves acc(&p.lastLayer, R55) && p.lastLayer != nil // @ preserves &p.scionLayer !== p.lastLayer ==> @@ -3392,11 +3427,11 @@ func (p *scionPacketProcessor) egressInterface( /*@ ghost oldPkt io.Pkt @*/ ) (e // @ ensures reserr == nil ==> // @ respr === processResult{} // posts for IO: -// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(ub) && p.scionLayer.EqAbsHeader(ub) -// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(ub)) == slayers.IsSupportedPkt(ub) -// @ ensures reserr == nil ==> absPkt(ub) == old(absPkt(ub)) +// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(sl.View(ub, 0, len(ub))) && p.scionLayer.EqAbsHeader(ub) +// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(sl.View(ub, 0, len(ub)))) == slayers.IsSupportedPkt(sl.View(ub, 0, len(ub))) +// @ ensures reserr == nil ==> absPkt(sl.View(ub, 0, len(ub))) == old(absPkt(sl.View(ub, 0, len(ub)))) // @ ensures reserr != nil && respr.OutPkt != nil ==> -// @ absIO_val(respr.OutPkt, respr.EgressID).isValUnsupported +// @ absIO_val(sl.View(respr.OutPkt, 0, len(respr.OutPkt)), respr.EgressID).isValUnsupported // @ decreases 0 if sync.IgnoreBlockingForTermination() func (p *scionPacketProcessor) validateEgressUp( // @ ghost ub []byte, @@ -3404,7 +3439,7 @@ func (p *scionPacketProcessor) validateEgressUp( // @ ghost startLL int, // @ ghost endLL int, ) (respr processResult, reserr error) { - // @ ghost oldPkt := absPkt(ub) + // @ ghost oldPkt := absPkt(sl.View(ub, 0, len(ub))) egressID := p.egressInterface( /*@ oldPkt @ */ ) // @ p.d.getBfdSessionsMem() // @ ghost if p.d.bfdSessions != nil { unfold acc(accBfdSession(p.d.bfdSessions), _) } @@ -3428,7 +3463,7 @@ func (p *scionPacketProcessor) validateEgressUp( } tmpRes, tmpErr := p.packSCMP(typ, 0, scmpP, serrors.New("bfd session down") /*@, ub , ubLL, startLL, endLL, @*/) // @ ghost if tmpErr != nil && tmpRes.OutPkt != nil { - // @ AbsUnsupportedPktIsUnsupportedVal(tmpRes.OutPkt, tmpRes.EgressID) + // @ AbsUnsupportedPktIsUnsupportedVal(sl.View(tmpRes.OutPkt, 0, len(tmpRes.OutPkt)), tmpRes.EgressID) // @ } return tmpRes, tmpErr } @@ -3475,24 +3510,24 @@ func (p *scionPacketProcessor) validateEgressUp( // @ ensures reserr == nil ==> // @ respr === processResult{} // constracts for IO-spec -// @ requires slayers.ValidPktMetaHdr(ub) && p.scionLayer.EqAbsHeader(ub) +// @ requires slayers.ValidPktMetaHdr(sl.View(ub, 0, len(ub))) && p.scionLayer.EqAbsHeader(ub) // @ requires p.DstIsLocalIngressID(ub) // @ requires p.LastHopLen(ub) -// @ requires absPkt(ub).PathNotFullyTraversed() -// @ requires p.EqAbsHopField(absPkt(ub)) -// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(ub) && p.scionLayer.EqAbsHeader(ub) +// @ requires absPkt(sl.View(ub, 0, len(ub))).PathNotFullyTraversed() +// @ requires p.EqAbsHopField(absPkt(sl.View(ub, 0, len(ub)))) +// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(sl.View(ub, 0, len(ub))) && p.scionLayer.EqAbsHeader(ub) // @ ensures reserr == nil ==> p.DstIsLocalIngressID(ub) // @ ensures reserr == nil ==> p.LastHopLen(ub) -// @ ensures reserr == nil ==> absPkt(ub).PathNotFullyTraversed() -// @ ensures reserr == nil ==> p.EqAbsHopField(absPkt(ub)) -// @ ensures reserr == nil ==> absPkt(ub) == old(absPkt(ub)) -// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(ub)) == slayers.IsSupportedPkt(ub) +// @ ensures reserr == nil ==> absPkt(sl.View(ub, 0, len(ub))).PathNotFullyTraversed() +// @ ensures reserr == nil ==> p.EqAbsHopField(absPkt(sl.View(ub, 0, len(ub)))) +// @ ensures reserr == nil ==> absPkt(sl.View(ub, 0, len(ub))) == old(absPkt(sl.View(ub, 0, len(ub)))) +// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(sl.View(ub, 0, len(ub)))) == slayers.IsSupportedPkt(sl.View(ub, 0, len(ub))) // @ ensures reserr != nil && respr.OutPkt != nil ==> -// @ absIO_val(respr.OutPkt, respr.EgressID).isValUnsupported +// @ absIO_val(sl.View(respr.OutPkt, 0, len(respr.OutPkt)), respr.EgressID).isValUnsupported // @ decreases func (p *scionPacketProcessor) handleIngressRouterAlert( /*@ ghost ub []byte, ghost ubLL []byte, ghost startLL int, ghost endLL int @*/ ) (respr processResult, reserr error) { - // @ reveal p.EqAbsHopField(absPkt(ub)) - // @ assert let fut := absPkt(ub).CurrSeg.Future in + // @ reveal p.EqAbsHopField(absPkt(sl.View(ub, 0, len(ub)))) + // @ assert let fut := absPkt(sl.View(ub, 0, len(ub))).CurrSeg.Future in // @ fut == seq[io.HF]{p.hopField.Abs()} ++ fut[1:] // @ ghost ubPath := p.scionLayer.UBPath(ub) // @ ghost startP := p.scionLayer.PathStartIdx(ub) @@ -3515,26 +3550,37 @@ func (p *scionPacketProcessor) handleIngressRouterAlert( /*@ ghost ub []byte, gh // @ sl.SplitRange_Bytes(ub, startP, endP, HalfPerm) // @ sl.SplitByIndex_Bytes(ub, 0, startP, slayers.CmnHdrLen, R54) // @ sl.Reslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) - // @ slayers.IsSupportedPktSubslice(ub, slayers.CmnHdrLen) + // @ slayers.IsSupportedPktSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) + // the view of the left piece is pinned across the modification of + // the path slice; the prefix asserts carry the common-header bytes, + // and with them IsSupportedPkt, from the state before to the state after + // @ ghost vHdrPre := sl.View(ub, 0, startP) + // @ assert sl.View(ub, 0, len(ub))[:startP] == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:slayers.CmnHdrLen] == vHdrPre[:slayers.CmnHdrLen] // @ p.AbsPktToSubSliceAbsPkt(ub, startP, endP) - // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ub, startP) + // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ub, sl.View(ub, 0, len(ub)), startP) + // @ assert sl.View(ub, 0, len(ub))[:startP] == sl.View(ub, 0, startP) // @ sl.SplitRange_Bytes(ub, startP, endP, HalfPerm) if err := p.path.SetHopField(p.hopField, int( /*@ unfolding acc(p.path.Mem(ubPath), R50) in (unfolding acc(p.path.Base.Mem(), R55) in @*/ p.path.PathMeta.CurrHF /*@ ) @*/) /*@ , ubPath @*/); err != nil { // @ sl.Unslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) // @ sl.CombineAtIndex_Bytes(ub, 0, startP, slayers.CmnHdrLen, R54) - // @ sl.CombineRange_Bytes(ub, startP, endP, writePerm) + // @ sl.CombineRangeWithViews_Bytes(ub, startP, endP, writePerm, sl.View(ub, 0, startP), sl.View(ub[startP:endP], 0, (endP)-(startP)), sl.View(ub, endP, len(ub))) // @ fold acc(p.scionLayer.Mem(ub), R20) // @ fold p.d.validResult(processResult{}, false) return processResult{}, serrors.WrapStr("update hop field", err) } - // @ sl.CombineRange_Bytes(ub, startP, endP, HalfPerm) - // @ slayers.IsSupportedPktSubslice(ub, slayers.CmnHdrLen) + // @ sl.CombineRangeWithViews_Bytes(ub, startP, endP, HalfPerm, sl.View(ub, 0, startP), sl.View(ub[startP:endP], 0, (endP)-(startP)), sl.View(ub, endP, len(ub))) + // @ assert sl.View(ub, 0, startP) == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:startP] == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:slayers.CmnHdrLen] == vHdrPre[:slayers.CmnHdrLen] + // @ slayers.IsSupportedPktSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) // @ sl.Unslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) // @ sl.CombineAtIndex_Bytes(ub, 0, startP, slayers.CmnHdrLen, R54) - // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ub, startP) + // @ assert sl.View(ub, 0, len(ub))[:startP] == sl.View(ub, 0, startP) + // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ub, sl.View(ub, 0, len(ub)), startP) // @ p.SubSliceAbsPktToAbsPkt(ub, startP, endP) - // @ absPktFutureLemma(ub) - // @ assert reveal p.EqAbsHopField(absPkt(ub)) + // @ absPktFutureLemma(sl.View(ub, 0, len(ub))) + // @ assert reveal p.EqAbsHopField(absPkt(sl.View(ub, 0, len(ub)))) // @ assert reveal p.LastHopLen(ub) // @ assert p.scionLayer.EqAbsHeader(ub) // @ sl.CombineRange_Bytes(ub, startP, endP, HalfPerm) @@ -3590,22 +3636,22 @@ func (p *scionPacketProcessor) ingressRouterAlertFlag() (res *bool) { // @ ensures reserr == nil ==> // @ respr === processResult{} // constracts for IO-spec -// @ requires slayers.ValidPktMetaHdr(ub) && p.scionLayer.EqAbsHeader(ub) -// @ requires absPkt(ub).PathNotFullyTraversed() -// @ requires p.EqAbsHopField(absPkt(ub)) -// @ requires p.EqAbsInfoField(absPkt(ub)) -// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(ub) && p.scionLayer.EqAbsHeader(ub) -// @ ensures reserr == nil ==> absPkt(ub).PathNotFullyTraversed() -// @ ensures reserr == nil ==> p.EqAbsHopField(absPkt(ub)) -// @ ensures reserr == nil ==> p.EqAbsInfoField(absPkt(ub)) -// @ ensures reserr == nil ==> absPkt(ub) == old(absPkt(ub)) -// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(ub)) == slayers.IsSupportedPkt(ub) +// @ requires slayers.ValidPktMetaHdr(sl.View(ub, 0, len(ub))) && p.scionLayer.EqAbsHeader(ub) +// @ requires absPkt(sl.View(ub, 0, len(ub))).PathNotFullyTraversed() +// @ requires p.EqAbsHopField(absPkt(sl.View(ub, 0, len(ub)))) +// @ requires p.EqAbsInfoField(absPkt(sl.View(ub, 0, len(ub)))) +// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(sl.View(ub, 0, len(ub))) && p.scionLayer.EqAbsHeader(ub) +// @ ensures reserr == nil ==> absPkt(sl.View(ub, 0, len(ub))).PathNotFullyTraversed() +// @ ensures reserr == nil ==> p.EqAbsHopField(absPkt(sl.View(ub, 0, len(ub)))) +// @ ensures reserr == nil ==> p.EqAbsInfoField(absPkt(sl.View(ub, 0, len(ub)))) +// @ ensures reserr == nil ==> absPkt(sl.View(ub, 0, len(ub))) == old(absPkt(sl.View(ub, 0, len(ub)))) +// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(sl.View(ub, 0, len(ub)))) == slayers.IsSupportedPkt(sl.View(ub, 0, len(ub))) // @ ensures reserr != nil && respr.OutPkt != nil ==> -// @ absIO_val(respr.OutPkt, respr.EgressID).isValUnsupported +// @ absIO_val(sl.View(respr.OutPkt, 0, len(respr.OutPkt)), respr.EgressID).isValUnsupported // @ decreases func (p *scionPacketProcessor) handleEgressRouterAlert( /*@ ghost ub []byte, ghost ubLL []byte, ghost startLL int, ghost endLL int @*/ ) (respr processResult, reserr error) { - // @ reveal p.EqAbsHopField(absPkt(ub)) - // @ assert let fut := absPkt(ub).CurrSeg.Future in + // @ reveal p.EqAbsHopField(absPkt(sl.View(ub, 0, len(ub)))) + // @ assert let fut := absPkt(sl.View(ub, 0, len(ub))).CurrSeg.Future in // @ fut == seq[io.HF]{p.hopField.Abs()} ++ fut[1:] // @ ghost ubPath := p.scionLayer.UBPath(ub) // @ ghost startP := p.scionLayer.PathStartIdx(ub) @@ -3617,7 +3663,7 @@ func (p *scionPacketProcessor) handleEgressRouterAlert( /*@ ghost ub []byte, gho // @ fold p.d.validResult(processResult{}, false) return processResult{}, nil } - egressID := p.egressInterface( /*@ absPkt(ub) @*/ ) + egressID := p.egressInterface( /*@ absPkt(sl.View(ub, 0, len(ub))) @*/ ) // @ p.d.getExternalMem() // @ if p.d.external != nil { unfold acc(accBatchConn(p.d.external), _) } if _, ok := p.d.external[egressID]; !ok { @@ -3632,27 +3678,38 @@ func (p *scionPacketProcessor) handleEgressRouterAlert( /*@ ghost ub []byte, gho // @ sl.SplitRange_Bytes(ub, startP, endP, HalfPerm) // @ sl.SplitByIndex_Bytes(ub, 0, startP, slayers.CmnHdrLen, R54) // @ sl.Reslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) - // @ slayers.IsSupportedPktSubslice(ub, slayers.CmnHdrLen) + // @ slayers.IsSupportedPktSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) + // the view of the left piece is pinned across the modification of + // the path slice; the prefix asserts carry the common-header bytes, + // and with them IsSupportedPkt, from the state before to the state after + // @ ghost vHdrPre := sl.View(ub, 0, startP) + // @ assert sl.View(ub, 0, len(ub))[:startP] == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:slayers.CmnHdrLen] == vHdrPre[:slayers.CmnHdrLen] // @ p.AbsPktToSubSliceAbsPkt(ub, startP, endP) - // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ub, startP) + // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ub, sl.View(ub, 0, len(ub)), startP) + // @ assert sl.View(ub, 0, len(ub))[:startP] == sl.View(ub, 0, startP) // @ sl.SplitRange_Bytes(ub, startP, endP, HalfPerm) if err := p.path.SetHopField(p.hopField, int( /*@ unfolding acc(p.path.Mem(ubPath), R50) in (unfolding acc(p.path.Base.Mem(), R55) in @*/ p.path.PathMeta.CurrHF /*@ ) @*/) /*@ , ubPath @*/); err != nil { // @ sl.Unslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) // @ sl.CombineAtIndex_Bytes(ub, 0, startP, slayers.CmnHdrLen, R54) - // @ sl.CombineRange_Bytes(ub, startP, endP, writePerm) + // @ sl.CombineRangeWithViews_Bytes(ub, startP, endP, writePerm, sl.View(ub, 0, startP), sl.View(ub[startP:endP], 0, (endP)-(startP)), sl.View(ub, endP, len(ub))) // @ fold acc(p.scionLayer.Mem(ub), R20) // @ fold p.d.validResult(processResult{}, false) return processResult{}, serrors.WrapStr("update hop field", err) } - // @ sl.CombineRange_Bytes(ub, startP, endP, HalfPerm) - // @ slayers.IsSupportedPktSubslice(ub, slayers.CmnHdrLen) + // @ sl.CombineRangeWithViews_Bytes(ub, startP, endP, HalfPerm, sl.View(ub, 0, startP), sl.View(ub[startP:endP], 0, (endP)-(startP)), sl.View(ub, endP, len(ub))) + // @ assert sl.View(ub, 0, startP) == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:startP] == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:slayers.CmnHdrLen] == vHdrPre[:slayers.CmnHdrLen] + // @ slayers.IsSupportedPktSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) // @ sl.Unslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) // @ sl.CombineAtIndex_Bytes(ub, 0, startP, slayers.CmnHdrLen, R54) - // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ub, startP) + // @ assert sl.View(ub, 0, len(ub))[:startP] == sl.View(ub, 0, startP) + // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ub, sl.View(ub, 0, len(ub)), startP) // @ p.SubSliceAbsPktToAbsPkt(ub, startP, endP) - // @ absPktFutureLemma(ub) - // @ assert reveal p.EqAbsHopField(absPkt(ub)) - // @ assert reveal p.EqAbsInfoField(absPkt(ub)) + // @ absPktFutureLemma(sl.View(ub, 0, len(ub))) + // @ assert reveal p.EqAbsHopField(absPkt(sl.View(ub, 0, len(ub)))) + // @ assert reveal p.EqAbsInfoField(absPkt(sl.View(ub, 0, len(ub)))) // @ sl.CombineRange_Bytes(ub, startP, endP, HalfPerm) // @ fold acc(p.scionLayer.Mem(ub), R20) return p.handleSCMPTraceRouteRequest(egressID /*@, ub, ubLL, startLL, endLL @*/) @@ -3680,9 +3737,9 @@ func (p *scionPacketProcessor) egressRouterAlertFlag() (res *bool) { // @ requires acc(&p.infoField, R20) // @ requires acc(&p.hopField, R20) // pres for IO: -// @ requires slayers.ValidPktMetaHdr(ubScionL) && p.scionLayer.EqAbsHeader(ubScionL) -// @ requires absPkt(ubScionL).PathNotFullyTraversed() -// @ requires p.EqAbsHopField(absPkt(ubScionL)) +// @ requires slayers.ValidPktMetaHdr(sl.View(ubScionL, 0, len(ubScionL))) && p.scionLayer.EqAbsHeader(ubScionL) +// @ requires absPkt(sl.View(ubScionL, 0, len(ubScionL))).PathNotFullyTraversed() +// @ requires p.EqAbsHopField(absPkt(sl.View(ubScionL, 0, len(ubScionL)))) // @ preserves acc(&p.ingressID, R22) // @ preserves acc(&p.mac, R20) && p.mac != nil && p.mac.Mem() // @ preserves acc(&p.macBuffers.scionInput, R20) @@ -3710,16 +3767,16 @@ func (p *scionPacketProcessor) egressRouterAlertFlag() (res *bool) { // @ respr === processResult{} // posts for IO: // @ ensures reserr == nil ==> old(p.DstIsLocalIngressID(ubScionL)) == p.DstIsLocalIngressID(ubScionL) -// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(ubScionL) && p.scionLayer.EqAbsHeader(ubScionL) -// @ ensures reserr == nil ==> absPkt(ubScionL).PathNotFullyTraversed() +// @ ensures reserr == nil ==> slayers.ValidPktMetaHdr(sl.View(ubScionL, 0, len(ubScionL))) && p.scionLayer.EqAbsHeader(ubScionL) +// @ ensures reserr == nil ==> absPkt(sl.View(ubScionL, 0, len(ubScionL))).PathNotFullyTraversed() // @ ensures reserr == nil ==> old(p.LastHopLen(ubScionL)) == p.LastHopLen(ubScionL) // @ ensures reserr == nil ==> -// @ old(p.EqAbsInfoField(absPkt(ubScionL))) == p.EqAbsInfoField(absPkt(ubScionL)) -// @ ensures reserr == nil ==> p.EqAbsHopField(absPkt(ubScionL)) -// @ ensures reserr == nil ==> absPkt(ubScionL) == old(absPkt(ubScionL)) -// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(ubScionL)) == slayers.IsSupportedPkt(ubScionL) +// @ old(p.EqAbsInfoField(absPkt(sl.View(ubScionL, 0, len(ubScionL))))) == p.EqAbsInfoField(absPkt(sl.View(ubScionL, 0, len(ubScionL)))) +// @ ensures reserr == nil ==> p.EqAbsHopField(absPkt(sl.View(ubScionL, 0, len(ubScionL)))) +// @ ensures reserr == nil ==> absPkt(sl.View(ubScionL, 0, len(ubScionL))) == old(absPkt(sl.View(ubScionL, 0, len(ubScionL)))) +// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(sl.View(ubScionL, 0, len(ubScionL)))) == slayers.IsSupportedPkt(sl.View(ubScionL, 0, len(ubScionL))) // @ ensures reserr != nil && respr.OutPkt != nil ==> -// @ absIO_val(respr.OutPkt, respr.EgressID).isValUnsupported +// @ absIO_val(sl.View(respr.OutPkt, 0, len(respr.OutPkt)), respr.EgressID).isValUnsupported // @ decreases func (p *scionPacketProcessor) handleSCMPTraceRouteRequest( interfaceID uint16 /*@, ghost ubScionL []byte, ghost ubLL []byte, ghost startLL int, ghost endLL int @*/) (respr processResult, reserr error) { @@ -3784,12 +3841,12 @@ func (p *scionPacketProcessor) handleSCMPTraceRouteRequest( } // @ ghost sl.CombineRange_Bytes(scionPld, 4, len(scionPld), R1) // @ ghost if !scionPldIsNil { - // @ sl.CombineRange_Bytes(ubLL, maybeStartPld, maybeEndPld, R1) + // @ sl.CombineRangeWithViews_Bytes(ubLL, maybeStartPld, maybeEndPld, R1, sl.View(ubLL, 0, maybeStartPld), sl.View(ubLL[maybeStartPld:maybeEndPld], 0, (maybeEndPld)-(maybeStartPld)), sl.View(ubLL, maybeEndPld, len(ubLL))) // @ } - // @ sl.CombineRange_Bytes(ubScionL, startLL, endLL, R1) + // @ sl.CombineRangeWithViews_Bytes(ubScionL, startLL, endLL, R1, sl.View(ubScionL, 0, startLL), sl.View(ubScionL[startLL:endLL], 0, (endLL)-(startLL)), sl.View(ubScionL, endLL, len(ubScionL))) tmpRes, tmpErr := p.packSCMP(slayers.SCMPTypeTracerouteReply, 0, &scmpP, (error)(nil) /*@ ,ubScionL, ubLL, startLL, endLL, @*/) // @ ghost if tmpErr != nil && tmpRes.OutPkt != nil { - // @ AbsUnsupportedPktIsUnsupportedVal(tmpRes.OutPkt, tmpRes.EgressID) + // @ AbsUnsupportedPktIsUnsupportedVal(sl.View(tmpRes.OutPkt, 0, len(tmpRes.OutPkt)), tmpRes.EgressID) // @ } return tmpRes, tmpErr } @@ -3825,15 +3882,15 @@ func (p *scionPacketProcessor) handleSCMPTraceRouteRequest( // @ ensures reserr == nil ==> // @ respr === processResult{} // contracts for IO-spec -// @ requires slayers.ValidPktMetaHdr(ubScionL) && p.scionLayer.EqAbsHeader(ubScionL) -// @ requires absPkt(ubScionL).PathNotFullyTraversed() +// @ requires slayers.ValidPktMetaHdr(sl.View(ubScionL, 0, len(ubScionL))) && p.scionLayer.EqAbsHeader(ubScionL) +// @ requires absPkt(sl.View(ubScionL, 0, len(ubScionL))).PathNotFullyTraversed() // @ ensures reserr == nil ==> -// @ slayers.ValidPktMetaHdr(ubScionL) && p.scionLayer.EqAbsHeader(ubScionL) -// @ ensures reserr == nil ==> absPkt(ubScionL).PathNotFullyTraversed() -// @ ensures reserr == nil ==> absPkt(ubScionL) == old(absPkt(ubScionL)) -// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(ubScionL)) == slayers.IsSupportedPkt(ubScionL) +// @ slayers.ValidPktMetaHdr(sl.View(ubScionL, 0, len(ubScionL))) && p.scionLayer.EqAbsHeader(ubScionL) +// @ ensures reserr == nil ==> absPkt(sl.View(ubScionL, 0, len(ubScionL))).PathNotFullyTraversed() +// @ ensures reserr == nil ==> absPkt(sl.View(ubScionL, 0, len(ubScionL))) == old(absPkt(sl.View(ubScionL, 0, len(ubScionL)))) +// @ ensures reserr == nil ==> old(slayers.IsSupportedPkt(sl.View(ubScionL, 0, len(ubScionL)))) == slayers.IsSupportedPkt(sl.View(ubScionL, 0, len(ubScionL))) // @ ensures reserr != nil && respr.OutPkt != nil ==> -// @ absIO_val(respr.OutPkt, respr.EgressID).isValUnsupported +// @ absIO_val(sl.View(respr.OutPkt, 0, len(respr.OutPkt)), respr.EgressID).isValUnsupported // @ decreases func (p *scionPacketProcessor) validatePktLen( /*@ ghost ubScionL []byte, ghost ubLL []byte, ghost startLL int, ghost endLL int @*/ ) (respr processResult, reserr error) { // @ unfold acc(p.scionLayer.Mem(ubScionL), R20) @@ -3851,7 +3908,7 @@ func (p *scionPacketProcessor) validatePktLen( /*@ ghost ubScionL []byte, ghost /*@ ubScionL, ubLL, startLL, endLL, @*/ ) // @ ghost if tmpErr != nil && tmpRes.OutPkt != nil { - // @ AbsUnsupportedPktIsUnsupportedVal(tmpRes.OutPkt, tmpRes.EgressID) + // @ AbsUnsupportedPktIsUnsupportedVal(sl.View(tmpRes.OutPkt, 0, len(tmpRes.OutPkt)), tmpRes.EgressID) // @ } return tmpRes, tmpErr } @@ -3906,12 +3963,12 @@ func (p *scionPacketProcessor) validatePktLen( /*@ ghost ubScionL []byte, ghost // @ requires p.scionLayer.EqAbsHeader(ub) && p.scionLayer.EqPathType(ub) && p.scionLayer.ValidScionInitSpec(ub) // @ requires acc(ioLock.LockP(), _) // @ requires ioLock.LockInv() == SharedInv{dp, ioSharedArg} -// @ requires let absPkt := absIO_val(ub, p.ingressID) in +// @ requires let absPkt := absIO_val(sl.View(ub, 0, len(ub)), p.ingressID) in // @ absPkt.isValPkt ==> ElemWitness(ioSharedArg.IBufY, path.ifsToIO_ifs(p.ingressID), absPkt.ValPkt_2) // @ ensures reserr == nil && newAbsPkt.isValPkt ==> // @ ElemWitness(ioSharedArg.OBufY, newAbsPkt.ValPkt_1, newAbsPkt.ValPkt_2) // @ ensures respr.OutPkt != nil ==> -// @ newAbsPkt == absIO_val(respr.OutPkt, respr.EgressID) +// @ newAbsPkt == absIO_val(sl.View(respr.OutPkt, 0, len(respr.OutPkt)), respr.EgressID) // @ ensures reserr != nil && respr.OutPkt != nil ==> // @ newAbsPkt.isValUnsupported // @ ensures (respr.OutPkt == nil) == (newAbsPkt == io.ValUnit{}) @@ -3932,12 +3989,12 @@ func (p *scionPacketProcessor) process( return r, err /*@, false, absReturnErr(r) @*/ } // @ ghost var oldPkt io.Pkt - // @ ghost if(slayers.IsSupportedPkt(ub)) { - // @ absIO_valLemma(ub, p.ingressID) - // @ oldPkt = absIO_val(ub, p.ingressID).ValPkt_2 + // @ ghost if(slayers.IsSupportedPkt(sl.View(ub, 0, len(ub)))) { + // @ absIO_valLemma(sl.View(ub, 0, len(ub)), p.ingressID) + // @ oldPkt = absIO_val(sl.View(ub, 0, len(ub)), p.ingressID).ValPkt_2 // @ } else { - // @ absPktFutureLemma(ub) - // @ oldPkt = absPkt(ub) + // @ absPktFutureLemma(sl.View(ub, 0, len(ub))) + // @ oldPkt = absPkt(sl.View(ub, 0, len(ub))) // @ } // @ nextPkt := oldPkt if r, err := p.validateHopExpiry( /*@ ub, ubLL, startLL, endLL @*/ ); err != nil { @@ -3965,8 +4022,8 @@ func (p *scionPacketProcessor) process( // @ p.scionLayer.DowngradePerm(ub) return processResult{}, err /*@, false, absReturnErr(processResult{}) @*/ } - // @ assert absPkt(ub) == AbsUpdateNonConsDirIngressSegID(oldPkt, path.ifsToIO_ifs(p.ingressID)) - // @ nextPkt = absPkt(ub) + // @ assert absPkt(sl.View(ub, 0, len(ub))) == AbsUpdateNonConsDirIngressSegID(oldPkt, path.ifsToIO_ifs(p.ingressID)) + // @ nextPkt = absPkt(sl.View(ub, 0, len(ub))) // @ AbsValidateIngressIDLemma(oldPkt, nextPkt, path.ifsToIO_ifs(p.ingressID)) if r, err := p.verifyCurrentMAC( /*@ dp, ub, ubLL, startLL, endLL @*/ ); err != nil { // @ p.scionLayer.DowngradePerm(ub) @@ -3977,7 +4034,7 @@ func (p *scionPacketProcessor) process( // @ p.scionLayer.DowngradePerm(ub) return r, err /*@, false, absReturnErr(r) @*/ } - // @ assert nextPkt == absPkt(ub) + // @ assert nextPkt == absPkt(sl.View(ub, 0, len(ub))) // Inbound: pkts destined to the local IA. // @ p.d.getLocalIA() if /*@ unfolding acc(p.scionLayer.Mem(ub), R50) in (unfolding acc(p.scionLayer.HeaderMem(ub[slayers.CmnHdrLen:]), R55) in @*/ p.scionLayer.DstIA /*@ ) @*/ == p.d.localIA { @@ -3997,10 +4054,10 @@ func (p *scionPacketProcessor) process( // @ unfold p.d.validResult(r, aliasesUb) // @ fold p.d.validResult(processResult{OutConn: p.d.internal, OutAddr: a, OutPkt: p.rawPkt}, aliasesUb) // @ assert ub === p.rawPkt - // @ ghost if(slayers.IsSupportedPkt(ub)) { + // @ ghost if(slayers.IsSupportedPkt(sl.View(ub, 0, len(ub)))) { // @ InternalEnterEvent(oldPkt, path.ifsToIO_ifs(p.ingressID), nextPkt, none[io.Ifs], ioLock, ioSharedArg, dp) // @ } - // @ newAbsPkt = reveal absIO_val(p.rawPkt, 0) + // @ newAbsPkt = reveal absIO_val(sl.View(p.rawPkt, 0, len(p.rawPkt)), 0) return processResult{OutConn: p.d.internal, OutAddr: a, OutPkt: p.rawPkt}, nil /*@, aliasesUb, newAbsPkt @*/ } // Outbound: pkts leaving the local IA. @@ -4015,9 +4072,9 @@ func (p *scionPacketProcessor) process( // @ fold p.d.validResult(processResult{}, false) return r, err /*@, false, absReturnErr(r) @*/ } - // @ assert absPkt(ub) == AbsDoXover(nextPkt) + // @ assert absPkt(sl.View(ub, 0, len(ub))) == AbsDoXover(nextPkt) // @ AbsValidateIngressIDXoverLemma(nextPkt, AbsDoXover(nextPkt), path.ifsToIO_ifs(p.ingressID)) - // @ nextPkt = absPkt(ub) + // @ nextPkt = absPkt(sl.View(ub, 0, len(ub))) if r, err := p.validateHopExpiry( /*@ ub, ubLL, startLL, endLL @*/ ); err != nil { // @ p.scionLayer.DowngradePerm(ub) return r, serrors.WithCtx(err, "info", "after xover") /*@, false, absReturnErr(r) @*/ @@ -4047,12 +4104,12 @@ func (p *scionPacketProcessor) process( // @ p.scionLayer.DowngradePerm(ub) return r, err /*@, false, absReturnErr(r) @*/ } - // @ assert nextPkt == absPkt(ub) + // @ assert nextPkt == absPkt(sl.View(ub, 0, len(ub))) if r, err := p.validateEgressUp( /*@ ub, ubLL, startLL, endLL @*/ ); err != nil { // @ p.scionLayer.DowngradePerm(ub) return r, err /*@, false, absReturnErr(r) @*/ } - // @ assert nextPkt == absPkt(ub) + // @ assert nextPkt == absPkt(sl.View(ub, 0, len(ub))) egressID := p.egressInterface( /*@ nextPkt @*/ ) // @ assert AbsEgressInterfaceConstraint(nextPkt, path.ifsToIO_ifs(egressID)) // @ p.d.getExternalMem() @@ -4065,16 +4122,16 @@ func (p *scionPacketProcessor) process( return processResult{}, err /*@, false, absReturnErr(processResult{}) @*/ } // @ p.d.InDomainExternalInForwardingMetrics(egressID) - // @ assert absPkt(ub) == AbsProcessEgress(nextPkt) - // @ nextPkt = absPkt(ub) - // @ ghost if(slayers.IsSupportedPkt(ub)) { + // @ assert absPkt(sl.View(ub, 0, len(ub))) == AbsProcessEgress(nextPkt) + // @ nextPkt = absPkt(sl.View(ub, 0, len(ub))) + // @ ghost if(slayers.IsSupportedPkt(sl.View(ub, 0, len(ub)))) { // @ ghost if(!p.segmentChange) { // @ ExternalEnterOrExitEvent(oldPkt, path.ifsToIO_ifs(p.ingressID), nextPkt, path.ifsToIO_ifs(egressID), ioLock, ioSharedArg, dp) // @ } else { // @ XoverEvent(oldPkt, path.ifsToIO_ifs(p.ingressID), nextPkt, path.ifsToIO_ifs(egressID), ioLock, ioSharedArg, dp) // @ } // @ } - // @ newAbsPkt = reveal absIO_val(p.rawPkt, egressID) + // @ newAbsPkt = reveal absIO_val(sl.View(p.rawPkt, 0, len(p.rawPkt)), egressID) // @ fold p.d.validResult(processResult{EgressID: egressID, OutConn: c, OutPkt: p.rawPkt}, false) return processResult{EgressID: egressID, OutConn: c, OutPkt: p.rawPkt}, nil /*@, false, newAbsPkt @*/ } @@ -4085,14 +4142,14 @@ func (p *scionPacketProcessor) process( // @ ghost if p.d.internalNextHops != nil { unfold acc(accAddr(p.d.internalNextHops), _) } if a, ok := p.d.internalNextHops[egressID]; ok { // @ p.d.getInternal() - // @ ghost if(slayers.IsSupportedPkt(ub)) { + // @ ghost if(slayers.IsSupportedPkt(sl.View(ub, 0, len(ub)))) { // @ if(!p.segmentChange) { // @ InternalEnterEvent(oldPkt, path.ifsToIO_ifs(p.ingressID), nextPkt, none[io.Ifs], ioLock, ioSharedArg, dp) // @ } else { // @ XoverEvent(oldPkt, path.ifsToIO_ifs(p.ingressID), nextPkt, none[io.Ifs], ioLock, ioSharedArg, dp) // @ } // @ } - // @ newAbsPkt = reveal absIO_val(p.rawPkt, 0) + // @ newAbsPkt = reveal absIO_val(sl.View(p.rawPkt, 0, len(p.rawPkt)), 0) // @ fold p.d.validResult(processResult{OutConn: p.d.internal, OutAddr: a, OutPkt: p.rawPkt}, false) return processResult{OutConn: p.d.internal, OutAddr: a, OutPkt: p.rawPkt}, nil /*@, false, newAbsPkt @*/ } @@ -4109,7 +4166,7 @@ func (p *scionPacketProcessor) process( /*@ ub, ubLL, startLL, endLL, @*/ ) // @ ghost if err != nil && tmp.OutPkt != nil { - // @ AbsUnsupportedPktIsUnsupportedVal(tmp.OutPkt, tmp.EgressID) + // @ AbsUnsupportedPktIsUnsupportedVal(sl.View(tmp.OutPkt, 0, len(tmp.OutPkt)), tmp.EgressID) // @ } // @ p.scionLayer.DowngradePerm(ub) return tmp, err /*@, false, absReturnErr(tmp) @*/ @@ -4142,10 +4199,10 @@ func (p *scionPacketProcessor) process( // @ ensures reserr != nil ==> reserr.ErrorMem() // contracts for IO-spec // @ requires p.scionLayer.EqPathType(p.rawPkt) -// @ requires !slayers.IsSupportedPkt(p.rawPkt) +// @ requires !slayers.IsSupportedPkt(sl.View(p.rawPkt, 0, len(p.rawPkt))) // @ ensures (respr.OutPkt == nil) == (newAbsPkt == io.ValUnit{}) // @ ensures respr.OutPkt != nil ==> -// @ newAbsPkt == absIO_val(respr.OutPkt, respr.EgressID) && +// @ newAbsPkt == absIO_val(sl.View(respr.OutPkt, 0, len(respr.OutPkt)), respr.EgressID) && // @ newAbsPkt.isValUnsupported // @ decreases 0 if sync.IgnoreBlockingForTermination() func (p *scionPacketProcessor) processOHP() (respr processResult, reserr error /*@ , ghost addrAliasesPkt bool, ghost newAbsPkt io.Val @*/) { @@ -4247,7 +4304,7 @@ func (p *scionPacketProcessor) processOHP() (respr processResult, reserr error / // @ p.d.InDomainExternalInForwardingMetrics(ohp.FirstHop.ConsEgress) // @ fold p.d.validResult(processResult{EgressID: ohp.FirstHop.ConsEgress, OutConn: c, OutPkt: p.rawPkt}, false) return processResult{EgressID: ohp.FirstHop.ConsEgress, OutConn: c, OutPkt: p.rawPkt}, - nil /*@ , false, reveal absIO_val(respr.OutPkt, respr.EgressID) @*/ + nil /*@ , false, reveal absIO_val(sl.View(respr.OutPkt, 0, len(respr.OutPkt)), respr.EgressID) @*/ } // TODO parameter problem invalid interface // @ establishCannotRoute() @@ -4312,7 +4369,7 @@ func (p *scionPacketProcessor) processOHP() (respr processResult, reserr error / // @ p.d.getInternal() // @ assert p.d.internal != nil ==> acc(p.d.internal.Mem(), _) // @ fold p.d.validResult(processResult{OutConn: p.d.internal, OutAddr: a, OutPkt: p.rawPkt}, addrAliases) - return processResult{OutConn: p.d.internal, OutAddr: a, OutPkt: p.rawPkt}, nil /*@ , addrAliases, reveal absIO_val(respr.OutPkt, 0) @*/ + return processResult{OutConn: p.d.internal, OutAddr: a, OutPkt: p.rawPkt}, nil /*@ , addrAliases, reveal absIO_val(sl.View(respr.OutPkt, 0, len(respr.OutPkt)), 0) @*/ } // @ requires acc(d.Mem(), _) @@ -4403,12 +4460,12 @@ func addEndhostPort(dst *net.IPAddr) (res *net.UDPAddr) { // @ preserves sl.Bytes(buffer.UBuf(), 0, len(buffer.UBuf())) // pres for IO: // @ requires s.EqPathType(rawPkt) -// @ requires !slayers.IsSupportedPkt(rawPkt) +// @ requires !slayers.IsSupportedPkt(sl.View(rawPkt, 0, len(rawPkt))) // @ ensures sl.Bytes(rawPkt, 0, len(rawPkt)) // @ ensures acc(s.Mem(rawPkt), R00) // @ ensures res != nil ==> res.ErrorMem() // post for IO: -// @ ensures res == nil ==> !slayers.IsSupportedPkt(rawPkt) +// @ ensures res == nil ==> !slayers.IsSupportedPkt(sl.View(rawPkt, 0, len(rawPkt))) // @ decreases // (VerifiedSCION) the type of 's' was changed from slayers.SCION to *slayers.SCION. This makes // specs a lot easier and, makes the implementation faster as well by avoiding passing large data-structures @@ -4420,25 +4477,42 @@ func updateSCIONLayer(rawPkt []byte, s *slayers.SCION, buffer gopacket.Serialize if err := s.SerializeTo(buffer, gopacket.SerializeOptions{} /*@ , rawPkt @*/); err != nil { return err } - // @ reveal slayers.IsSupportedRawPkt(buffer.View()) + // @ reveal slayers.IsSupportedPkt(buffer.View()) // TODO(lukedirtwalker): We should add a method to the scion layers // which can write into the existing buffer, see also the discussion in // https://fsnets.slack.com/archives/C8ADBBG0J/p1592805884250700 rawContents := buffer.Bytes() - // @ assert !(reveal slayers.IsSupportedPkt(rawContents)) + // @ assert !(reveal slayers.IsSupportedPkt(sl.View(rawContents, 0, len(rawContents)))) + // IsSupportedPkt only depends on bytes 4 and 8 of the packet; the + // ground facts below carry them from the serialization buffer's view + // to the view of rawPkt after the copy + // @ sl.ViewElems(rawContents, 0, len(rawContents), R21) + // @ ghost vC := sl.View(rawContents, 0, len(rawContents)) + // @ ghost c4 := sl.GetByte(rawContents, 0, len(rawContents), 4) + // @ ghost c8 := sl.GetByte(rawContents, 0, len(rawContents), 8) + // @ assert vC[4] == c4 && vC[8] == c8 // @ s.ValidSizeOhpUb(rawPkt) // @ assert len(rawContents) <= len(rawPkt) // @ unfold sl.Bytes(rawPkt, 0, len(rawPkt)) // @ unfold acc(sl.Bytes(rawContents, 0, len(rawContents)), R20) + // @ assert rawContents[4] == c4 && rawContents[8] == c8 // (VerifiedSCION) proving that the reslicing operation below is safe // was tricky and required enriching (non-modularly) the invariants of *onehop.Path // and *slayers.SCION. // @ assert forall i int :: { &rawPkt[:len(rawContents)][i] }{ &rawPkt[i] } 0 <= i && i < len(rawContents) ==> // @ &rawPkt[i] == &rawPkt[:len(rawContents)][i] copy(rawPkt[:len(rawContents)], rawContents /*@ , R20 @*/) + // @ assert rawPkt[4] == c4 && rawPkt[8] == c8 // @ fold sl.Bytes(rawPkt, 0, len(rawPkt)) + // @ assert sl.GetByte(rawPkt, 0, len(rawPkt), 4) == c4 + // @ assert sl.GetByte(rawPkt, 0, len(rawPkt), 8) == c8 + // @ sl.ViewElems(rawPkt, 0, len(rawPkt), writePerm) + // @ ghost vP := sl.View(rawPkt, 0, len(rawPkt)) + // @ assert vP[4] == sl.GetByte(rawPkt, 0, len(rawPkt), 4) + // @ assert vP[8] == sl.GetByte(rawPkt, 0, len(rawPkt), 8) + // @ assert vP[4] == vC[4] && vP[8] == vC[8] // @ fold acc(sl.Bytes(rawContents, 0, len(rawContents)), R20) - // @ assert !(reveal slayers.IsSupportedPkt(rawPkt)) + // @ assert !(reveal slayers.IsSupportedPkt(sl.View(rawPkt, 0, len(rawPkt)))) return nil } @@ -4554,7 +4628,7 @@ func (b *bfdSend) Send(bfd *layers.BFD) error { // @ result === p.buffer.UBuf() // @ ensures reserr != nil && reserr.ErrorMem() // @ ensures result != nil ==> -// @ !slayers.IsSupportedPkt(result) +// @ !slayers.IsSupportedPkt(sl.View(result, 0, len(result))) // @ decreases func (p *scionPacketProcessor) prepareSCMP( typ slayers.SCMPType, diff --git a/router/io-spec-lemmas.gobra b/router/io-spec-lemmas.gobra index 81ffb39d1..968b547fd 100644 --- a/router/io-spec-lemmas.gobra +++ b/router/io-spec-lemmas.gobra @@ -28,13 +28,12 @@ import ( ) ghost -preserves acc(sl.Bytes(raw, 0, len(raw)), R55) ensures slayers.ValidPktMetaHdr(raw) && slayers.IsSupportedPkt(raw) ==> absIO_val(raw, ingressID).isValPkt && absIO_val(raw, ingressID).ValPkt_2 == absPkt(raw) && absPkt(raw).PathNotFullyTraversed() decreases -func absIO_valLemma(raw []byte, ingressID uint16) { +func absIO_valLemma(raw seq[byte], ingressID uint16) { if(slayers.ValidPktMetaHdr(raw) && slayers.IsSupportedPkt(raw)){ absIO := reveal absIO_val(raw, ingressID) assert absIO.isValPkt @@ -44,19 +43,16 @@ func absIO_valLemma(raw []byte, ingressID uint16) { } ghost -requires acc(sl.Bytes(raw, 0, len(raw)), R56) requires slayers.ValidPktMetaHdr(raw) -ensures acc(sl.Bytes(raw, 0, len(raw)), R56) ensures slayers.ValidPktMetaHdr(raw) ensures absPkt(raw).PathNotFullyTraversed() decreases -func absPktFutureLemma(raw []byte) { +func absPktFutureLemma(raw seq[byte]) { reveal slayers.ValidPktMetaHdr(raw) headerOffset := slayers.GetAddressOffset(raw) headerOffsetWithMetaLen := headerOffset + scion.MetaLen - assert forall k int :: {&raw[headerOffset:headerOffset+scion.MetaLen][k]} 0 <= k && k < scion.MetaLen ==> &raw[headerOffset:headerOffset+scion.MetaLen][k] == &raw[headerOffset + k] - hdr := (unfolding acc(sl.Bytes(raw, 0, len(raw)), R56) in - binary.BigEndian.Uint32(raw[headerOffset:headerOffset+scion.MetaLen])) + hdr := binary.BigEndian.Uint32Spec(raw[headerOffset], + raw[headerOffset+1], raw[headerOffset+2], raw[headerOffset+3]) metaHdr := scion.DecodedFrom(hdr) currInfIdx := int(metaHdr.CurrINF) currHfIdx := int(metaHdr.CurrHF) @@ -118,12 +114,12 @@ requires p.scionLayer.Mem(ub) requires acc(&p.d) && p.d.Mem() requires acc(&p.ingressID) requires sl.Bytes(ub, 0, len(ub)) -requires slayers.ValidPktMetaHdr(ub) +requires slayers.ValidPktMetaHdr(sl.View(ub, 0, len(ub))) decreases pure func (p *scionPacketProcessor) LastHopLen(ub []byte) bool { return (unfolding p.scionLayer.Mem(ub) in (unfolding p.scionLayer.HeaderMem(ub[slayers.CmnHdrLen:]) in p.scionLayer.DstIA) == (unfolding p.d.Mem() in p.d.localIA)) ==> - len(absPkt(ub).CurrSeg.Future) == 1 + len(absPkt(sl.View(ub, 0, len(ub))).CurrSeg.Future) == 1 } //TODO: Does not work with --disableNL --unsafeWildcardoptimization @@ -132,7 +128,7 @@ requires acc(p.scionLayer.Mem(ub), R50) requires acc(&p.d, R55) && acc(p.d.Mem(), _) requires acc(&p.ingressID, R55) requires acc(sl.Bytes(ub, 0, len(ub)), R56) -requires slayers.ValidPktMetaHdr(ub) +requires slayers.ValidPktMetaHdr(sl.View(ub, 0, len(ub))) requires p.DstIsLocalIngressID(ub) requires p.LastHopLen(ub) requires (unfolding acc(p.scionLayer.Mem(ub), R50) in @@ -142,9 +138,9 @@ ensures acc(p.scionLayer.Mem(ub), R50) ensures acc(&p.d, R55) && acc(p.d.Mem(), _) ensures acc(&p.ingressID, R55) ensures acc(sl.Bytes(ub, 0, len(ub)), R56) -ensures slayers.ValidPktMetaHdr(ub) +ensures slayers.ValidPktMetaHdr(sl.View(ub, 0, len(ub))) ensures p.ingressID != 0 -ensures len(absPkt(ub).CurrSeg.Future) == 1 +ensures len(absPkt(sl.View(ub, 0, len(ub))).CurrSeg.Future) == 1 decreases func (p* scionPacketProcessor) LocalDstLemma(ub []byte) { reveal p.DstIsLocalIngressID(ub) @@ -222,23 +218,22 @@ ensures acc(sl.Bytes(ub[start:end], 0, len(ub[start:end])), R50) ensures acc(&p.path, R55) && acc(p.path.Mem(ub[start:end]), R55) ensures start == p.scionLayer.PathStartIdx(ub) ensures end == p.scionLayer.PathEndIdx(ub) -ensures p.path.GetBase(ub[start:end]).EqAbsHeader(ub[start:end]) +ensures p.path.GetBase(ub[start:end]).EqAbsHeader(sl.View(ub[start:end], 0, len(ub[start:end]))) ensures p.path.GetBase(ub[start:end]).WeaklyValid() -ensures p.scionLayer.ValidHeaderOffset(ub, len(ub)) +ensures p.scionLayer.ValidHeaderOffset(ub, sl.View(ub, 0, len(ub))) decreases func (p* scionPacketProcessor) EstablishEqAbsHeader(ub []byte, start int, end int) { - unfold acc(sl.Bytes(ub, 0, len(ub)), R56) - unfold acc(sl.Bytes(ub[start:end], 0, len(ub[start:end])), R56) + sl.ViewOfSubslice(ub, start, end, R56) + assert sl.View(ub[start:end], 0, len(ub[start:end])) == + sl.View(ub, 0, len(ub))[start:end] unfold acc(p.scionLayer.Mem(ub), R56) unfold acc(p.path.Mem(ub[start:end]), R56) reveal p.scionLayer.EqAbsHeader(ub) reveal p.scionLayer.ValidScionInitSpec(ub) - assert reveal p.scionLayer.ValidHeaderOffset(ub, len(ub)) - assert p.path.GetBase(ub[start:end]).EqAbsHeader(ub[start:end]) + assert reveal p.scionLayer.ValidHeaderOffset(ub, sl.View(ub, 0, len(ub))) + assert p.path.GetBase(ub[start:end]).EqAbsHeader(sl.View(ub[start:end], 0, len(ub[start:end]))) fold acc(p.path.Mem(ub[start:end]), R56) fold acc(p.scionLayer.Mem(ub), R56) - fold acc(sl.Bytes(ub[start:end], 0, len(ub[start:end])), R56) - fold acc(sl.Bytes(ub, 0, len(ub)), R56) } ghost @@ -248,7 +243,7 @@ requires acc(sl.Bytes(ub, 0, len(ub)), R50) requires acc(sl.Bytes(ub[start:end], 0, len(ub[start:end])), R50) requires acc(&p.path, R55) && acc(p.path.Mem(ub[start:end]), R55) requires p.path === p.scionLayer.GetPath(ub) -requires slayers.ValidPktMetaHdr(ub) +requires slayers.ValidPktMetaHdr(sl.View(ub, 0, len(ub))) requires start == p.scionLayer.PathStartIdx(ub) requires end == p.scionLayer.PathEndIdx(ub) requires p.scionLayer.EqAbsHeader(ub) @@ -256,34 +251,32 @@ ensures acc(sl.Bytes(ub, 0, len(ub)), R50) ensures acc(p.scionLayer.Mem(ub), R55) ensures acc(sl.Bytes(ub[start:end], 0, len(ub[start:end])), R50) ensures acc(&p.path, R55) && acc(p.path.Mem(ub[start:end]), R55) -ensures slayers.ValidPktMetaHdr(ub) +ensures slayers.ValidPktMetaHdr(sl.View(ub, 0, len(ub))) ensures p.scionLayer.EqAbsHeader(ub) ensures start == p.scionLayer.PathStartIdx(ub) ensures end == p.scionLayer.PathEndIdx(ub) -ensures scion.validPktMetaHdr(ub[start:end]) -ensures p.path.GetBase(ub[start:end]).EqAbsHeader(ub[start:end]) -ensures p.scionLayer.ValidHeaderOffset(ub, len(ub)) +ensures scion.validPktMetaHdr(sl.View(ub[start:end], 0, len(ub[start:end]))) +ensures p.path.GetBase(ub[start:end]).EqAbsHeader(sl.View(ub[start:end], 0, len(ub[start:end]))) +ensures p.scionLayer.ValidHeaderOffset(ub, sl.View(ub, 0, len(ub))) ensures p.path === p.scionLayer.GetPath(ub) -ensures absPkt(ub) == p.path.absPkt(ub[start:end]) +ensures absPkt(sl.View(ub, 0, len(ub))) == p.path.absPkt(sl.View(ub[start:end], 0, len(ub[start:end]))) decreases func (p* scionPacketProcessor) AbsPktToSubSliceAbsPkt(ub []byte, start int, end int) { - unfold acc(sl.Bytes(ub, 0, len(ub)), R56) - unfold acc(sl.Bytes(ub[start:end], 0, len(ub[start:end])), R56) - reveal slayers.ValidPktMetaHdr(ub) + v := sl.View(ub, 0, len(ub)) + sl.ViewOfSubslice(ub, start, end, R56) + assert sl.View(ub[start:end], 0, len(ub[start:end])) == v[start:end] + reveal slayers.ValidPktMetaHdr(v) reveal p.scionLayer.EqAbsHeader(ub) - assert reveal scion.validPktMetaHdr(ub[start:end]) + assert reveal scion.validPktMetaHdr(v[start:end]) unfold acc(p.scionLayer.Mem(ub), R56) - reveal p.scionLayer.ValidHeaderOffset(ub, len(ub)) - assert p.path.GetBase(ub[start:end]).EqAbsHeader(ub[start:end]) + reveal p.scionLayer.ValidHeaderOffset(ub, v) + assert p.path.GetBase(ub[start:end]).EqAbsHeader(v[start:end]) fold acc(p.scionLayer.Mem(ub), R56) - assert start == slayers.GetAddressOffset(ub) + assert start == slayers.GetAddressOffset(v) - hdr1 := binary.BigEndian.Uint32(ub[start:start+scion.MetaLen]) - hdr2 := binary.BigEndian.Uint32(ub[start:end][:scion.MetaLen]) - assert hdr1 == hdr2 - hdr := hdr1 - fold acc(sl.Bytes(ub[start:end], 0, len(ub[start:end])), R56) - fold acc(sl.Bytes(ub, 0, len(ub)), R56) + hdr := binary.BigEndian.Uint32Spec(v[start], v[start+1], v[start+2], v[start+3]) + assert hdr == binary.BigEndian.Uint32Spec(v[start:end][0], v[start:end][1], + v[start:end][2], v[start:end][3]) headerOffsetWithMetaLen := start + scion.MetaLen metaHdr := scion.DecodedFrom(hdr) currInfIdx := int(metaHdr.CurrINF) @@ -297,11 +290,11 @@ func (p* scionPacketProcessor) AbsPktToSubSliceAbsPkt(ub []byte, start int, end numINF := segs.NumInfoFields() offset := scion.HopFieldOffset(numINF, prevSegLen, headerOffsetWithMetaLen) - scion.WidenCurrSeg(ub, offset, currInfIdx, currHfIdx-prevSegLen, segLen, headerOffsetWithMetaLen, start, end) - scion.WidenLeftSeg(ub, currInfIdx + 1, segs, headerOffsetWithMetaLen, start, end) - scion.WidenMidSeg(ub, currInfIdx + 2, segs, headerOffsetWithMetaLen, start, end) - scion.WidenRightSeg(ub, currInfIdx - 1, segs, headerOffsetWithMetaLen, start, end) - assert reveal absPkt(ub) == reveal p.path.absPkt(ub[start:end]) + scion.WidenCurrSeg(v, offset, currInfIdx, currHfIdx-prevSegLen, segLen, headerOffsetWithMetaLen, start, end) + scion.WidenLeftSeg(v, currInfIdx + 1, segs, headerOffsetWithMetaLen, start, end) + scion.WidenMidSeg(v, currInfIdx + 2, segs, headerOffsetWithMetaLen, start, end) + scion.WidenRightSeg(v, currInfIdx - 1, segs, headerOffsetWithMetaLen, start, end) + assert reveal absPkt(v) == reveal p.path.absPkt(v[start:end]) } ghost @@ -311,43 +304,41 @@ requires acc(sl.Bytes(ub, 0, len(ub)), R50) requires acc(sl.Bytes(ub[start:end], 0, len(ub[start:end])), R50) requires acc(&p.path, R55) && acc(p.path.Mem(ub[start:end]), R55) requires p.path === p.scionLayer.GetPath(ub) -requires scion.validPktMetaHdr(ub[start:end]) +requires scion.validPktMetaHdr(sl.View(ub[start:end], 0, len(ub[start:end]))) requires start == p.scionLayer.PathStartIdx(ub) requires end == p.scionLayer.PathEndIdx(ub) -requires p.path.GetBase(ub[start:end]).EqAbsHeader(ub[start:end]) -requires p.scionLayer.ValidHeaderOffset(ub, len(ub)) +requires p.path.GetBase(ub[start:end]).EqAbsHeader(sl.View(ub[start:end], 0, len(ub[start:end]))) +requires p.scionLayer.ValidHeaderOffset(ub, sl.View(ub, 0, len(ub))) ensures acc(sl.Bytes(ub, 0, len(ub)), R50) ensures acc(p.scionLayer.Mem(ub), R55) ensures acc(sl.Bytes(ub[start:end], 0, len(ub[start:end])), R50) ensures acc(&p.path, R55) && acc(p.path.Mem(ub[start:end]), R55) -ensures slayers.ValidPktMetaHdr(ub) +ensures slayers.ValidPktMetaHdr(sl.View(ub, 0, len(ub))) ensures start == p.scionLayer.PathStartIdx(ub) ensures end == p.scionLayer.PathEndIdx(ub) -ensures scion.validPktMetaHdr(ub[start:end]) +ensures scion.validPktMetaHdr(sl.View(ub[start:end], 0, len(ub[start:end]))) ensures p.scionLayer.EqAbsHeader(ub) ensures p.path === p.scionLayer.GetPath(ub) -ensures absPkt(ub) == p.path.absPkt(ub[start:end]) -ensures p.scionLayer.ValidHeaderOffset(ub, len(ub)) +ensures absPkt(sl.View(ub, 0, len(ub))) == p.path.absPkt(sl.View(ub[start:end], 0, len(ub[start:end]))) +ensures p.scionLayer.ValidHeaderOffset(ub, sl.View(ub, 0, len(ub))) decreases func (p* scionPacketProcessor) SubSliceAbsPktToAbsPkt(ub []byte, start int, end int){ - unfold acc(sl.Bytes(ub, 0, len(ub)), R56) - unfold acc(sl.Bytes(ub[start:end], 0, len(ub[start:end])), R56) + v := sl.View(ub, 0, len(ub)) + sl.ViewOfSubslice(ub, start, end, R56) + assert sl.View(ub[start:end], 0, len(ub[start:end])) == v[start:end] unfold acc(p.scionLayer.Mem(ub), R56) unfold acc(p.scionLayer.Path.Mem(ub[start:end]), R56) - reveal p.scionLayer.ValidHeaderOffset(ub, len(ub)) + reveal p.scionLayer.ValidHeaderOffset(ub, v) assert reveal p.scionLayer.EqAbsHeader(ub) fold acc(p.scionLayer.Path.Mem(ub[start:end]), R56) fold acc(p.scionLayer.Mem(ub), R56) - reveal scion.validPktMetaHdr(ub[start:end]) - assert reveal slayers.ValidPktMetaHdr(ub) - assert start == slayers.GetAddressOffset(ub) + reveal scion.validPktMetaHdr(v[start:end]) + assert reveal slayers.ValidPktMetaHdr(v) + assert start == slayers.GetAddressOffset(v) headerOffsetWithMetaLen := start + scion.MetaLen - hdr1 := binary.BigEndian.Uint32(ub[start:start+scion.MetaLen]) - hdr2 := binary.BigEndian.Uint32(ub[start:end][:scion.MetaLen]) - assert hdr1 == hdr2 - hdr := hdr1 - fold acc(sl.Bytes(ub[start:end], 0, len(ub[start:end])), R56) - fold acc(sl.Bytes(ub, 0, len(ub)), R56) + hdr := binary.BigEndian.Uint32Spec(v[start], v[start+1], v[start+2], v[start+3]) + assert hdr == binary.BigEndian.Uint32Spec(v[start:end][0], v[start:end][1], + v[start:end][2], v[start:end][3]) metaHdr := scion.DecodedFrom(hdr) currInfIdx := int(metaHdr.CurrINF) @@ -361,11 +352,11 @@ func (p* scionPacketProcessor) SubSliceAbsPktToAbsPkt(ub []byte, start int, end numINF := segs.NumInfoFields() offset := scion.HopFieldOffset(numINF, prevSegLen, headerOffsetWithMetaLen) - scion.WidenCurrSeg(ub, offset, currInfIdx, currHfIdx-prevSegLen, segLen, headerOffsetWithMetaLen, start, end) - scion.WidenLeftSeg(ub, currInfIdx + 1, segs, headerOffsetWithMetaLen, start, end) - scion.WidenMidSeg(ub, currInfIdx + 2, segs, headerOffsetWithMetaLen, start, end) - scion.WidenRightSeg(ub, currInfIdx - 1, segs, headerOffsetWithMetaLen, start, end) - assert reveal absPkt(ub) == reveal p.path.absPkt(ub[start:end]) + scion.WidenCurrSeg(v, offset, currInfIdx, currHfIdx-prevSegLen, segLen, headerOffsetWithMetaLen, start, end) + scion.WidenLeftSeg(v, currInfIdx + 1, segs, headerOffsetWithMetaLen, start, end) + scion.WidenMidSeg(v, currInfIdx + 2, segs, headerOffsetWithMetaLen, start, end) + scion.WidenRightSeg(v, currInfIdx - 1, segs, headerOffsetWithMetaLen, start, end) + assert reveal absPkt(v) == reveal p.path.absPkt(v[start:end]) } ghost diff --git a/router/io-spec.gobra b/router/io-spec.gobra index e861dc014..fa0cde027 100644 --- a/router/io-spec.gobra +++ b/router/io-spec.gobra @@ -32,15 +32,14 @@ import ( ghost opaque -requires sl.Bytes(raw, 0, len(raw)) requires slayers.ValidPktMetaHdr(raw) decreases -pure func absPkt(raw []byte) (res io.Pkt) { +pure func absPkt(raw seq[byte]) (res io.Pkt) { return let _ := reveal slayers.ValidPktMetaHdr(raw) in let headerOffset := slayers.GetAddressOffset(raw) in let headerOffsetWithMetaLen := headerOffset + scion.MetaLen in - let hdr := (unfolding sl.Bytes(raw, 0, len(raw)) in - binary.BigEndian.Uint32(raw[headerOffset:headerOffset+scion.MetaLen])) in + let hdr := binary.BigEndian.Uint32Spec(raw[headerOffset], + raw[headerOffset+1], raw[headerOffset+2], raw[headerOffset+3]) in let metaHdr := scion.DecodedFrom(hdr) in let currInfIdx := int(metaHdr.CurrINF) in let currHfIdx := int(metaHdr.CurrHF) in @@ -61,11 +60,10 @@ pure func absPkt(raw []byte) (res io.Pkt) { } ghost -requires sl.Bytes(raw, 0, len(raw)) ensures val.isValUnsupported ensures val.ValUnsupported_1 == path.ifsToIO_ifs(ingressID) decreases -pure func absValUnsupported(raw []byte, ingressID uint16) (val io.Val) { +pure func absValUnsupported(raw seq[byte], ingressID uint16) (val io.Val) { return io.Val(io.ValUnsupported { path.ifsToIO_ifs(ingressID), io.Unit{}, @@ -74,22 +72,19 @@ pure func absValUnsupported(raw []byte, ingressID uint16) (val io.Val) { ghost opaque -requires sl.Bytes(raw, 0, len(raw)) ensures val.isValPkt || val.isValUnsupported decreases -pure func absIO_val(raw []byte, ingressID uint16) (val io.Val) { +pure func absIO_val(raw seq[byte], ingressID uint16) (val io.Val) { return (reveal slayers.ValidPktMetaHdr(raw) && slayers.IsSupportedPkt(raw)) ? io.Val(io.ValPkt{path.ifsToIO_ifs(ingressID), absPkt(raw)}) : absValUnsupported(raw, ingressID) } ghost -requires acc(sl.Bytes(raw, 0, len(raw)), R56) requires !slayers.IsSupportedPkt(raw) -ensures acc(sl.Bytes(raw, 0, len(raw)), R56) ensures absIO_val(raw, ingressID).isValUnsupported decreases -func AbsUnsupportedPktIsUnsupportedVal(raw []byte, ingressID uint16) { +func AbsUnsupportedPktIsUnsupportedVal(raw seq[byte], ingressID uint16) { reveal absIO_val(raw, ingressID) } @@ -99,7 +94,7 @@ requires respr.OutPkt != nil ==> decreases pure func absReturnErr(respr processResult) (val io.Val) { return respr.OutPkt == nil ? io.ValUnit{} : - absIO_val(respr.OutPkt, respr.EgressID) + absIO_val(sl.View(respr.OutPkt, 0, len(respr.OutPkt)), respr.EgressID) } ghost @@ -210,5 +205,5 @@ requires sl.Bytes(msg.GetFstBuffer(), 0, len(msg.GetFstBuffer())) decreases pure func MsgToAbsVal(msg *ipv4.Message, ingressID uint16) (res io.Val) { return unfolding msg.Mem() in - absIO_val(msg.Buffers[0], ingressID) + absIO_val(sl.View(msg.Buffers[0], 0, len(msg.Buffers[0])), ingressID) } diff --git a/router/widen-lemma.gobra b/router/widen-lemma.gobra index 8c0b31711..4707c71ef 100644 --- a/router/widen-lemma.gobra +++ b/router/widen-lemma.gobra @@ -17,9 +17,7 @@ package router import ( - sl "verification/utils/slices" "verification/io" - . "verification/utils/definitions" "verification/dependencies/encoding/binary" "github.com/scionproto/scion/pkg/slayers" "github.com/scionproto/scion/pkg/slayers/path" @@ -28,16 +26,14 @@ import ( // Some things in this file can be simplified. Nonetheless, the important definition here // is absIO_valWidenLemma. Everything else can be seen as an implementation detail. +// Since packets are abstracted with views (mathematical sequences), these lemmas +// require no permissions at all. ghost -requires 0 <= length && length <= len(raw) -requires acc(sl.Bytes(raw, 0, len(raw)), R49) -requires acc(sl.Bytes(raw[:length], 0, len(raw[:length])), R49) -ensures acc(sl.Bytes(raw, 0, len(raw)), R49) -ensures acc(sl.Bytes(raw[:length], 0, len(raw[:length])), R49) -ensures absIO_val(raw[:length], ingressID).isValPkt ==> +requires 0 <= length && length <= len(raw) +ensures absIO_val(raw[:length], ingressID).isValPkt ==> absIO_val(raw[:length], ingressID) == absIO_val(raw, ingressID) decreases -func absIO_valWidenLemma(raw []byte, ingressID uint16, length int) { +func absIO_valWidenLemma(raw seq[byte], ingressID uint16, length int) { var ret1 io.Val var ret2 io.Val @@ -62,73 +58,54 @@ func absIO_valWidenLemma(raw []byte, ingressID uint16, length int) { ghost requires 0 <= length && length <= len(raw) -requires acc(sl.Bytes(raw, 0, len(raw)), R51) -requires acc(sl.Bytes(raw[:length], 0, len(raw[:length])), R51) requires slayers.ValidPktMetaHdr(raw[:length]) -ensures acc(sl.Bytes(raw, 0, len(raw)), R51) -ensures acc(sl.Bytes(raw[:length], 0, len(raw[:length])), R51) ensures slayers.ValidPktMetaHdr(raw) decreases -func ValidPktMetaHdrWidenLemma(raw []byte, length int) { - unfold acc(sl.Bytes(raw, 0, len(raw)), R56) - unfold acc(sl.Bytes(raw[:length], 0, len(raw[:length])), R56) +func ValidPktMetaHdrWidenLemma(raw seq[byte], length int) { reveal slayers.ValidPktMetaHdr(raw[:length]) + assert raw[:length][5] == raw[5] && raw[:length][9] == raw[9] ret1 := reveal slayers.ValidPktMetaHdr(raw) ret2 := reveal slayers.ValidPktMetaHdr(raw[:length]) assert ret1 == ret2 - fold acc(sl.Bytes(raw, 0, len(raw)), R56) - fold acc(sl.Bytes(raw[:length], 0, len(raw[:length])), R56) } ghost requires 0 <= length && length <= len(raw) -requires acc(sl.Bytes(raw, 0, len(raw)), R51) -requires acc(sl.Bytes(raw[:length], 0, len(raw[:length])), R51) requires slayers.IsSupportedPkt(raw[:length]) -ensures acc(sl.Bytes(raw, 0, len(raw)), R51) -ensures acc(sl.Bytes(raw[:length], 0, len(raw[:length])), R51) ensures slayers.IsSupportedPkt(raw) decreases -func IsSupportedPktWidenLemma(raw []byte, length int) { - unfold acc(sl.Bytes(raw, 0, len(raw)), R56) - unfold acc(sl.Bytes(raw[:length], 0, len(raw[:length])), R56) +func IsSupportedPktWidenLemma(raw seq[byte], length int) { reveal slayers.IsSupportedPkt(raw[:length]) + assert raw[:length][4] == raw[4] && raw[:length][8] == raw[8] ret1 := reveal slayers.IsSupportedPkt(raw) ret2 := reveal slayers.IsSupportedPkt(raw[:length]) assert ret1 == ret2 - fold acc(sl.Bytes(raw, 0, len(raw)), R56) - fold acc(sl.Bytes(raw[:length], 0, len(raw[:length])), R56) } ghost -requires 0 <= length && length <= len(raw) -requires acc(sl.Bytes(raw, 0, len(raw)), R50) -requires acc(sl.Bytes(raw[:length], 0, len(raw[:length])), R50) +requires 0 <= length && length <= len(raw) requires slayers.ValidPktMetaHdr(raw) requires slayers.ValidPktMetaHdr(raw[:length]) -ensures acc(sl.Bytes(raw, 0, len(raw)), R50) -ensures acc(sl.Bytes(raw[:length], 0, len(raw[:length])), R50) ensures slayers.ValidPktMetaHdr(raw) ensures slayers.ValidPktMetaHdr(raw[:length]) ensures absPkt(raw) == absPkt(raw[:length]) decreases -func absPktWidenLemma(raw []byte, length int) { +func absPktWidenLemma(raw seq[byte], length int) { reveal slayers.ValidPktMetaHdr(raw) reveal slayers.ValidPktMetaHdr(raw[:length]) - unfold acc(sl.Bytes(raw, 0, len(raw)), R51) - unfold acc(sl.Bytes(raw[:length], 0, len(raw[:length])), R51) headerOffset1 := slayers.GetAddressOffset(raw) headerOffset2 := slayers.GetAddressOffset(raw[:length]) + assert raw[:length][9] == raw[9] assert headerOffset1 == headerOffset2 headerOffset := headerOffset1 headerOffsetWithMetaLen := headerOffset + scion.MetaLen - hdr1 := binary.BigEndian.Uint32(raw[headerOffset:headerOffset+scion.MetaLen]) - hdr2 := binary.BigEndian.Uint32(raw[:length][headerOffset:headerOffset+scion.MetaLen]) + hdr1 := binary.BigEndian.Uint32Spec(raw[headerOffset], + raw[headerOffset+1], raw[headerOffset+2], raw[headerOffset+3]) + hdr2 := binary.BigEndian.Uint32Spec(raw[:length][headerOffset], + raw[:length][headerOffset+1], raw[:length][headerOffset+2], raw[:length][headerOffset+3]) assert hdr1 == hdr2 hdr := hdr1 - fold acc(sl.Bytes(raw, 0, len(raw)), R51) - fold acc(sl.Bytes(raw[:length], 0, len(raw[:length])), R51) metaHdr := scion.DecodedFrom(hdr) currInfIdx := int(metaHdr.CurrINF) diff --git a/verification/utils/seqs/seqs.gobra b/verification/utils/seqs/seqs.gobra index e2c336a80..97acceee4 100644 --- a/verification/utils/seqs/seqs.gobra +++ b/verification/utils/seqs/seqs.gobra @@ -39,10 +39,33 @@ ensures forall i int :: { res[i] } 0 <= i && i < size ==> res[i] == nil decreases _ pure func NewSeqByteSlice(size int) (res seq[[]byte]) +// SubSeqOfSubSeq proves that reslicing a subsequence yields the same +// sequence as directly slicing the original sequence with the composed +// indices. +ghost +requires 0 <= start && start <= a +requires a <= b && b <= length && length <= len(raw) +ensures raw[a:b] == raw[start:length][a - start : b - start] +decreases +func SubSeqOfSubSeq(raw seq[byte], a int, b int, start int, length int) { + s1 := raw[a:b] + s2 := raw[start:length][a - start : b - start] + assert len(s1) == len(s2) + assert forall i int :: { s1[i] } 0 <= i && i < b - a ==> + s1[i] == raw[a + i] + assert forall i int :: { s2[i] } 0 <= i && i < b - a ==> + s2[i] == raw[start:length][a - start + i] + assert forall i int :: { s2[i] } 0 <= i && i < b - a ==> + s2[i] == raw[a + i] + assert s1 == s2 +} + +// Deprecated: use sl.View directly. ToSeqByte is kept as an alias for +// the view of a whole slice while its remaining clients are migrated. ghost requires acc(sl.Bytes(ub, 0, len(ub)), _) ensures len(res) == len(ub) -ensures forall i int :: { res[i] } 0 <= i && i < len(ub) ==> - res[i] == sl.GetByte(ub, 0, len(ub), i) -decreases _ -pure func ToSeqByte(ub []byte) (res seq[byte]) \ No newline at end of file +decreases +pure func ToSeqByte(ub []byte) (res seq[byte]) { + return sl.View(ub, 0, len(ub)) +} \ No newline at end of file diff --git a/verification/utils/slices/slices.gobra b/verification/utils/slices/slices.gobra index f8c21ed66..fa84f0b25 100644 --- a/verification/utils/slices/slices.gobra +++ b/verification/utils/slices/slices.gobra @@ -39,17 +39,278 @@ pure func GetByte(s []byte, start int, end int, i int) byte { return unfolding Bytes(s, start, end) in s[i] } +// View abstracts the contents of the range [start, end) of s, as +// guarded by the predicate instance Bytes(s, start, end), into a +// mathematical sequence of bytes. All content-related reasoning +// should be performed on views: given a view of the predicate +// instance one holds, the bytes of any subrange are obtained by +// (pure) sequence slicing, instead of by manipulating predicate +// instances, which cannot be done in pure contexts. +// In the same way that Bytes hides the quantified permissions to the +// elements of a slice, View deliberately hides the quantified +// relation between the sequence and the contents of the slice: its +// only visible property is the length of the result. The elementwise +// characterization is established explicitly, where needed, by +// calling ViewElems. +ghost +opaque +requires acc(Bytes(s, start, end), _) +ensures len(res) == end - start +decreases +pure func View(s []byte, start int, end int) (res seq[byte]) { + return unfolding acc(Bytes(s, start, end), _) in ViewAux(s, start, end) +} + +// ViewElems establishes the elementwise characterization of +// View(s, start, end): it contains exactly the bytes of s in the +// range [start, end). +ghost +requires 0 < p +requires acc(Bytes(s, start, end), p) +ensures acc(Bytes(s, start, end), p) +ensures View(s, start, end) == old(View(s, start, end)) +ensures forall i int :: { View(s, start, end)[i] } 0 <= i && i < end - start ==> + View(s, start, end)[i] == GetByte(s, start, end, start + i) +ensures forall i int :: { old(GetByte(s, start, end, start + i)) } { GetByte(s, start, end, start + i) } 0 <= i && i < end - start ==> + GetByte(s, start, end, start + i) == old(GetByte(s, start, end, start + i)) +decreases +func ViewElems(s []byte, start int, end int, p perm) { + v := reveal View(s, start, end) + unfold acc(Bytes(s, start, end), p/2) + assert v == ViewAux(s, start, end) + ViewAuxElems(s, start, end, p/2) + assert v == ViewAux(s, start, end) + assert forall i int :: { v[i] } 0 <= i && i < end - start ==> + v[i] == s[start + i] + fold acc(Bytes(s, start, end), p/2) + assert forall i int :: { v[i] } 0 <= i && i < end - start ==> + v[i] == GetByte(s, start, end, start + i) +} + +// ViewAux computes the contents of the range [i, end) of s directly +// from the elementwise access permissions, so that the recursion does +// not require a predicate instance per subrange. Like View, it does +// not expose the contents of its result through a quantified +// postcondition; its elementwise characterization is established by +// ViewAuxElems. +ghost +requires 0 <= i && i <= end && end <= cap(s) +requires forall k int :: { &s[k] } i <= k && k < end ==> acc(&s[k], _) +ensures len(res) == end - i +decreases end - i +pure func ViewAux(s []byte, i int, end int) (res seq[byte]) { + return i == end ? seq[byte]{} : + seq[byte]{s[i]} ++ ViewAux(s, i + 1, end) +} + +// ViewAuxElems establishes the elementwise characterization of +// ViewAux(s, i, end): it contains exactly the bytes of s in the +// range [i, end). It moreover guarantees that the call does not +// change the bytes of s or the value of ViewAux: callers rely on +// these contract-carried equalities, since facts about the previous +// permission snapshot do not survive the call otherwise. +ghost +requires 0 < p +requires 0 <= i && i <= end && end <= cap(s) +preserves forall k int :: { &s[k] } i <= k && k < end ==> acc(&s[k], p) +ensures forall k int :: { &s[k] } i <= k && k < end ==> s[k] == old(s[k]) +ensures ViewAux(s, i, end) == old(ViewAux(s, i, end)) +ensures forall k int :: { ViewAux(s, i, end)[k] } 0 <= k && k < end - i ==> + ViewAux(s, i, end)[k] == s[i + k] +decreases end - i +func ViewAuxElems(s []byte, i int, end int, p perm) { + if i != end { + ViewAuxElems(s, i + 1, end, p) + assert s[i] == old(s[i]) + assert ViewAux(s, i + 1, end) == old(ViewAux(s, i + 1, end)) + assert ViewAux(s, i, end) == seq[byte]{s[i]} ++ ViewAux(s, i + 1, end) + assert old(ViewAux(s, i, end)) == old(seq[byte]{s[i]} ++ ViewAux(s, i + 1, end)) + } +} + +// ViewAuxSplit shows that the contents of the range [start, end) are +// the concatenation of the contents of [start, idx) and [idx, end). +// The proof is by recursion, so that no quantified facts about the +// contents are ever introduced. It additionally guarantees that the +// value of ViewAux over the whole range is not changed by the call, +// which is the fact SplitByIndex_Bytes needs. The preservation facts +// for the two subranges are provided by the companion lemma +// ViewAuxSplitParts; carrying all preservation facts in a single +// lemma makes the prover diverge. +ghost +requires 0 < p +requires 0 <= start && start <= idx && idx <= end && end <= cap(s) +preserves forall k int :: { &s[k] } start <= k && k < end ==> acc(&s[k], p) +ensures ViewAux(s, start, end) == old(ViewAux(s, start, end)) +ensures ViewAux(s, start, end) == ViewAux(s, start, idx) ++ ViewAux(s, idx, end) +decreases idx - start +func ViewAuxSplit(s []byte, start int, idx int, end int, p perm) { + if start == idx { + assert ViewAux(s, start, idx) == seq[byte]{} + assert ViewAux(s, start, end) == ViewAux(s, idx, end) + } else { + ViewAuxSplit(s, start + 1, idx, end, p) + assert s[start] == old(s[start]) + assert ViewAux(s, start, end) == + seq[byte]{s[start]} ++ ViewAux(s, start + 1, end) + assert old(ViewAux(s, start, end)) == + old(seq[byte]{s[start]} ++ ViewAux(s, start + 1, end)) + assert ViewAux(s, start, idx) == + seq[byte]{s[start]} ++ ViewAux(s, start + 1, idx) + assert ViewAux(s, start, end) == + seq[byte]{s[start]} ++ (ViewAux(s, start + 1, idx) ++ ViewAux(s, idx, end)) + } +} + +// ViewAuxSplitParts is the companion of ViewAuxSplit used by +// CombineAtIndex_Bytes: it establishes the same concatenation +// equation, but promises that the values of ViewAux over the two +// subranges are not changed by the call. +ghost +requires 0 < p +requires 0 <= start && start <= idx && idx <= end && end <= cap(s) +preserves forall k int :: { &s[k] } start <= k && k < end ==> acc(&s[k], p) +ensures ViewAux(s, start, idx) == old(ViewAux(s, start, idx)) +ensures ViewAux(s, idx, end) == old(ViewAux(s, idx, end)) +ensures ViewAux(s, start, end) == ViewAux(s, start, idx) ++ ViewAux(s, idx, end) +decreases idx - start +func ViewAuxSplitParts(s []byte, start int, idx int, end int, p perm) { + if start == idx { + assert ViewAux(s, start, idx) == seq[byte]{} + assert ViewAux(s, start, end) == ViewAux(s, idx, end) + } else { + ViewAuxSplitParts(s, start + 1, idx, end, p) + assert s[start] == old(s[start]) + assert ViewAux(s, start, idx) == + seq[byte]{s[start]} ++ ViewAux(s, start + 1, idx) + assert old(ViewAux(s, start, idx)) == + old(seq[byte]{s[start]} ++ ViewAux(s, start + 1, idx)) + assert ViewAux(s, start, end) == + seq[byte]{s[start]} ++ ViewAux(s, start + 1, end) + assert ViewAux(s, start, end) == + seq[byte]{s[start]} ++ (ViewAux(s, start + 1, idx) ++ ViewAux(s, idx, end)) + } +} + +// ViewAuxReslice shows that the contents of the range [i, end) of s +// coincide with the contents of the range [i - start, end - start) of +// the subslice s[start:length]. The proof is by recursion, so that no +// quantified facts about the contents are ever introduced. Like +// ViewAuxElems, it guarantees that the bytes of s and the values of +// ViewAux are not changed by the call. +ghost +requires 0 < p +requires 0 <= start && start <= i && i <= end && end <= length && length <= cap(s) +preserves forall k int :: { &s[k] } i <= k && k < end ==> acc(&s[k], p) +ensures forall k int :: { &s[k] } i <= k && k < end ==> s[k] == old(s[k]) +ensures ViewAux(s, i, end) == old(ViewAux(s, i, end)) +ensures let _ := AssertSliceOverlap(s, start, length) in + ViewAux(s, i, end) == ViewAux(s[start:length], i - start, end - start) +decreases end - i +func ViewAuxReslice(s []byte, start int, length int, i int, end int, p perm) { + AssertSliceOverlap(s, start, length) + if i == end { + assert ViewAux(s, i, end) == seq[byte]{} + assert ViewAux(s[start:length], i - start, end - start) == seq[byte]{} + } else { + assert &s[start:length][i - start] == &s[i] + ViewAuxReslice(s, start, length, i + 1, end, p) + assert s[i] == old(s[i]) + assert ViewAux(s, i + 1, end) == old(ViewAux(s, i + 1, end)) + assert ViewAux(s, i, end) == seq[byte]{s[i]} ++ ViewAux(s, i + 1, end) + assert old(ViewAux(s, i, end)) == old(seq[byte]{s[i]} ++ ViewAux(s, i + 1, end)) + assert ViewAux(s[start:length], i - start, end - start) == + seq[byte]{s[start:length][i - start]} ++ ViewAux(s[start:length], i - start + 1, end - start) + } +} + +// ViewEqFromElements derives an equality between View(s, start, end) +// and a sequence known to be elementwise equal to it. This is the +// extensionality principle used to reconstruct views after predicate +// instances are folded, e.g., after writes to the underlying buffer. +ghost +requires 0 < p +requires acc(Bytes(s, start, end), p) +requires len(other) == end - start +requires forall i int :: { other[i] } 0 <= i && i < end - start ==> + other[i] == GetByte(s, start, end, start + i) +ensures acc(Bytes(s, start, end), p) +ensures View(s, start, end) == other +decreases +func ViewEqFromElements(s []byte, start int, end int, other seq[byte], p perm) { + // calling ViewElems with half of the held fraction retains a + // positive fraction of the predicate instance, which pins its + // snapshot: the GetByte and View applications before and after the + // call are then the same terms, and the precondition characterizes + // the current state directly + ViewElems(s, start, end, p/2) + v := View(s, start, end) + assert forall i int :: { other[i] } 0 <= i && i < end - start ==> + other[i] == GetByte(s, start, end, start + i) + assert forall i int :: { v[i] } 0 <= i && i < end - start ==> + v[i] == GetByte(s, start, end, start + i) + assert forall i int :: { other[i] } 0 <= i && i < end - start ==> + v[i] == other[i] + assert v == other +} + +// ViewOfSubslice relates the view of a subslice, guarded by its own +// predicate instance, to the view of the original slice. Together +// with the view postconditions of the lemmas below, it makes all +// per-function "offset equality" and "widening" lemmas unnecessary: +// the view of a subslice is the subsequence of the view. +ghost +requires 0 < p +requires 0 <= start && start <= end && end <= len(s) +preserves acc(Bytes(s, 0, len(s)), p) +preserves acc(Bytes(s[start:end], 0, end - start), p) +ensures View(s[start:end], 0, end - start) == View(s, 0, len(s))[start:end] +decreases +func ViewOfSubslice(s []byte, start int, end int, p perm) { + // The proof composes the split and combine lemmas on half of the + // permissions to the instance covering all of s. Splitting derives + // a second predicate instance for s[start:end], whose view is a + // subsequence of the view of s by the postcondition of + // SplitRange_Bytes; since positive fractions of both instances of + // the subslice predicate are held throughout, both instances agree + // on the view of the subslice, and the derived instance can be + // combined back without changing any views. + vFull := View(s, 0, len(s)) + SplitRange_Bytes(s, start, end, p/2) + assert View(s[start:end], 0, end - start) == vFull[start:end] + CombineRange_Bytes(s, start, end, p/2) + assert View(s, 0, len(s)) == vFull + assert View(s[start:end], 0, end - start) == vFull[start:end] +} + ghost requires 0 < p requires acc(Bytes(s, start, end), p) requires start <= idx && idx <= end ensures acc(Bytes(s, start, idx), p) ensures acc(Bytes(s, idx, end), p) +ensures View(s, start, idx) == old(View(s, start, end))[:idx - start] +ensures View(s, idx, end) == old(View(s, start, end))[idx - start:] decreases func SplitByIndex_Bytes(s []byte, start int, end int, idx int, p perm) { + v := reveal View(s, start, end) unfold acc(Bytes(s, start, end), p) - fold acc(Bytes(s, start, idx), p) - fold acc(Bytes(s, idx, end), p) + assert v == ViewAux(s, start, end) + ViewAuxSplit(s, start, idx, end, p) + assert v == ViewAux(s, start, end) + assert v == ViewAux(s, start, idx) ++ ViewAux(s, idx, end) + assert len(ViewAux(s, start, idx)) == idx - start + // fold in two halves: the views of the freshly folded instances are + // related to ViewAux while the remaining half of the element + // permissions still makes ViewAux well-defined + fold acc(Bytes(s, start, idx), p/2) + fold acc(Bytes(s, idx, end), p/2) + assert reveal View(s, start, idx) == ViewAux(s, start, idx) + assert reveal View(s, idx, end) == ViewAux(s, idx, end) + fold acc(Bytes(s, start, idx), p/2) + fold acc(Bytes(s, idx, end), p/2) + assert View(s, start, idx) == v[:idx - start] + assert View(s, idx, end) == v[idx - start:] } ghost @@ -57,11 +318,23 @@ requires 0 < p requires acc(Bytes(s, start, idx), p) requires acc(Bytes(s, idx, end), p) ensures acc(Bytes(s, start, end), p) +ensures View(s, start, end) == + old(View(s, start, idx)) ++ old(View(s, idx, end)) decreases func CombineAtIndex_Bytes(s []byte, start int, end int, idx int, p perm) { + v1 := reveal View(s, start, idx) + v2 := reveal View(s, idx, end) unfold acc(Bytes(s, start, idx), p) unfold acc(Bytes(s, idx, end), p) - fold acc(Bytes(s, start, end), p) + assert v1 == ViewAux(s, start, idx) + assert v2 == ViewAux(s, idx, end) + ViewAuxSplitParts(s, start, idx, end, p) + assert v1 == ViewAux(s, start, idx) + assert v2 == ViewAux(s, idx, end) + fold acc(Bytes(s, start, end), p/2) + assert reveal View(s, start, end) == ViewAux(s, start, end) + fold acc(Bytes(s, start, end), p/2) + assert View(s, start, end) == v1 ++ v2 } ghost @@ -71,11 +344,19 @@ requires acc(Bytes(s, start, end), p) // the slice operation is well-formed requires unfolding acc(Bytes(s, start, end), p) in true ensures acc(Bytes(s[start:end], 0, len(s[start:end])), p) +ensures View(s[start:end], 0, end - start) == old(View(s, start, end)) decreases func Reslice_Bytes(s []byte, start int, end int, p perm) { + v := reveal View(s, start, end) unfold acc(Bytes(s, start, end), p) assert forall i int :: { &s[start:end][i] }{ &s[start + i] } 0 <= i && i < (end-start) ==> &s[start:end][i] == &s[start + i] - fold acc(Bytes(s[start:end], 0, len(s[start:end])), p) + assert v == ViewAux(s, start, end) + ViewAuxReslice(s, start, end, start, end, p) + assert v == ViewAux(s, start, end) + assert v == ViewAux(s[start:end], 0, end - start) + fold acc(Bytes(s[start:end], 0, len(s[start:end])), p/2) + assert reveal View(s[start:end], 0, end - start) == ViewAux(s[start:end], 0, end - start) + fold acc(Bytes(s[start:end], 0, len(s[start:end])), p/2) } ghost @@ -83,25 +364,40 @@ requires 0 < p requires 0 <= start && start <= end && end <= cap(s) requires acc(Bytes(s[start:end], 0, len(s[start:end])), p) ensures acc(Bytes(s, start, end), p) +ensures View(s, start, end) == old(View(s[start:end], 0, end - start)) decreases func Unslice_Bytes(s []byte, start int, end int, p perm) { + v := reveal View(s[start:end], 0, end - start) unfold acc(Bytes(s[start:end], 0, len(s[start:end])), p) assert 0 <= start && start <= end && end <= cap(s) assert forall i int :: { &s[start:end][i] } 0 <= i && i < len(s[start:end]) ==> acc(&s[start:end][i], p) assert forall i int :: { &s[start:end][i] }{ &s[start + i] } 0 <= i && i < len(s[start:end]) ==> &s[start:end][i] == &s[start + i] + assert v == ViewAux(s[start:end], 0, end - start) + ViewAuxElems(s[start:end], 0, end - start, p) + assert v == ViewAux(s[start:end], 0, end - start) + assert forall i int :: { &s[start:end][i] } 0 <= i && i < len(s[start:end]) ==> s[start:end][i] == v[i] invariant 0 <= j && j <= len(s[start:end]) invariant forall i int :: { &s[start:end][i] } j <= i && i < len(s[start:end]) ==> acc(&s[start:end][i], p) invariant forall i int :: { &s[start:end][i] }{ &s[start + i] } 0 <= i && i < len(s[start:end]) ==> &s[start:end][i] == &s[start + i] + invariant forall i int :: { &s[start:end][i] } j <= i && i < len(s[start:end]) ==> s[start:end][i] == v[i] invariant forall i int :: { &s[i] } start <= i && i < start+j ==> acc(&s[i], p) + invariant forall i int :: { &s[i] } start <= i && i < start+j ==> s[i] == v[i - start] decreases len(s[start:end]) - j for j := 0; j < len(s[start:end]); j++ { assert forall i int :: { &s[i] } start <= i && i < start+j ==> acc(&s[i], p) assert &s[start:end][j] == &s[start + j] assert acc(&s[start + j], p) + assert s[start + j] == v[j] assert forall i int :: { &s[i] } start <= i && i <= start+j ==> acc(&s[i], p) } - fold acc(Bytes(s, start, end), p) + ViewAuxElems(s, start, end, p) + assert forall k int :: { ViewAux(s, start, end)[k] } 0 <= k && k < end - start ==> + ViewAux(s, start, end)[k] == v[k] + assert v == ViewAux(s, start, end) + fold acc(Bytes(s, start, end), p/2) + assert reveal View(s, start, end) == ViewAux(s, start, end) + fold acc(Bytes(s, start, end), p/2) } ghost @@ -111,10 +407,18 @@ requires acc(Bytes(s, 0, len(s)), p) ensures acc(Bytes(s[start:end], 0, end-start), p) ensures acc(Bytes(s, 0, start), p) ensures acc(Bytes(s, end, len(s)), p) +ensures View(s[start:end], 0, end-start) == old(View(s, 0, len(s)))[start:end] +ensures View(s, 0, start) == old(View(s, 0, len(s)))[:start] +ensures View(s, end, len(s)) == old(View(s, 0, len(s)))[end:] decreases func SplitRange_Bytes(s []byte, start int, end int, p perm) { + v := View(s, 0, len(s)) SplitByIndex_Bytes(s, 0, len(s), start, p) SplitByIndex_Bytes(s, start, len(s), end, p) + assert View(s, start, end) == v[start:][:end - start] + assert v[start:][:end - start] == v[start:end] + assert View(s, end, len(s)) == v[start:][end - start:] + assert v[start:][end - start:] == v[end:] Reslice_Bytes(s, start, end, p) } @@ -132,6 +436,63 @@ func CombineRange_Bytes(s []byte, start int, end int, p perm) { CombineAtIndex_Bytes(s, 0, len(s), start, p) } +// CombineRangeWithViews_Bytes behaves like CombineRange_Bytes and +// additionally relates the view of the combined instance with the +// views of the three instances that are combined. The views of the +// pieces are passed as ghost parameters, bound by the preconditions +// in the state before the call: the postconditions then need no old() +// expressions, which do not re-check reliably under all verification +// configurations when the instances they depend on are consumed by +// the call. At call sites, passing View(s, 0, start), +// View(s[start:end], 0, end-start) and View(s, end, len(s)) satisfies +// the bindings trivially. +ghost +requires 0 < p +requires 0 <= start && start <= end && end <= len(s) +requires acc(Bytes(s[start:end], 0, end-start), p) +requires acc(Bytes(s, 0, start), p) +requires acc(Bytes(s, end, len(s)), p) +requires vl == View(s, 0, start) +requires vm == View(s[start:end], 0, end - start) +requires vr == View(s, end, len(s)) +ensures acc(Bytes(s, 0, len(s)), p) +ensures View(s, 0, len(s)) == vl ++ vm ++ vr +ensures View(s, 0, len(s))[:start] == vl +ensures View(s, 0, len(s))[start:end] == vm +ensures View(s, 0, len(s))[end:] == vr +decreases +func CombineRangeWithViews_Bytes(s []byte, start int, end int, p perm, ghost vl seq[byte], ghost vm seq[byte], ghost vr seq[byte]) { + Unslice_Bytes(s, start, end, p) + CombineAtIndex_Bytes(s, start, len(s), end, p) + CombineAtIndex_Bytes(s, 0, len(s), start, p) + assert View(s, 0, len(s)) == vl ++ (vm ++ vr) + assert len(vl) == start && len(vm) == end - start + assert View(s, 0, len(s))[:start] == vl + assert View(s, 0, len(s))[start:] == vm ++ vr + assert View(s, 0, len(s))[start:][:end - start] == vm + assert View(s, 0, len(s))[start:end] == View(s, 0, len(s))[start:][:end - start] + assert View(s, 0, len(s))[start:][end - start:] == vr + assert View(s, 0, len(s))[end:] == View(s, 0, len(s))[start:][end - start:] +} + +// CombineRangeNoView_Bytes behaves like CombineRange_Bytes, but does not +// relate the views of the combined predicate instances. Use this variant +// in contexts where heap-dependent functions cannot be evaluated in the +// old state of the call, e.g., when packaging magic wands. +ghost +requires 0 < p +requires 0 <= start && start <= end && end <= len(s) +requires acc(Bytes(s[start:end], 0, end-start), p) +requires acc(Bytes(s, 0, start), p) +requires acc(Bytes(s, end, len(s)), p) +ensures acc(Bytes(s, 0, len(s)), p) +decreases +func CombineRangeNoView_Bytes(s []byte, start int, end int, p perm) { + Unslice_Bytes(s, start, end, p) + CombineAtIndex_Bytes(s, start, len(s), end, p) + CombineAtIndex_Bytes(s, 0, len(s), start, p) +} + ghost ensures Bytes(nil, 0, 0) decreases diff --git a/verification/utils/slices/slices_test.gobra b/verification/utils/slices/slices_test.gobra index 399161928..dd114f362 100644 --- a/verification/utils/slices/slices_test.gobra +++ b/verification/utils/slices/slices_test.gobra @@ -22,4 +22,29 @@ func Bytes_test() { s := make([]byte, 10) fold Bytes(s, 0, 10) // assert false // fails +} + +func View_test() { + s := make([]byte, 10) + fold Bytes(s, 0, 10) + v := View(s, 0, 10) + assert len(v) == 10 + ViewElems(s, 0, 10, writePerm) + assert View(s, 0, 10)[3] == GetByte(s, 0, 10, 3) + assert v[3] == GetByte(s, 0, 10, 3) + + // splitting preserves the contents of the views + SplitByIndex_Bytes(s, 0, 10, 4, writePerm) + assert View(s, 0, 4) == v[:4] + assert View(s, 4, 10) == v[4:] + assert View(s, 0, 4)[2] == v[2] + CombineAtIndex_Bytes(s, 0, 10, 4, writePerm) + assert View(s, 0, 10) == v + + // reslicing preserves the contents of the views + SplitRange_Bytes(s, 2, 8, writePerm) + assert View(s[2:8], 0, 6) == v[2:8] + CombineRangeWithViews_Bytes(s, 2, 8, writePerm, + View(s, 0, 2), View(s[2:8], 0, 6), View(s, 8, 10)) + assert View(s, 0, 10) == v } \ No newline at end of file