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 77a131064..0c688ed15 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/epic/epic.go b/pkg/slayers/path/epic/epic.go index 8d33b9649..12d4a976a 100644 --- a/pkg/slayers/path/epic/epic.go +++ b/pkg/slayers/path/epic/epic.go @@ -175,9 +175,14 @@ func (p *Path) DecodeFromBytes(b []byte) (r error) { //@ ghost var base0 scion.Base //@ ghost if ret == nil { //@ base0 = p.ScionPath.GetBase(b[MetadataLen:]) - //@ assert base0.EqAbsHeader(b[MetadataLen:]) + //@ assert base0.EqAbsHeader(sl.View(b[MetadataLen:], 0, len(b[MetadataLen:]))) //@ assert base0.WeaklyValid() //@ assert scion.MetaLen <= len(b) - MetadataLen + // pin the elementwise characterization of the sub-path view before exposing + // its bytes, retaining a positive fraction so the snapshot stays fixed + //@ sl.ViewElems(b[MetadataLen:], 0, len(b[MetadataLen:]), R56) + //@ assert forall i int :: { sl.View(b[MetadataLen:], 0, len(b[MetadataLen:]))[i] } 0 <= i && i < scion.MetaLen ==> + //@ sl.View(b[MetadataLen:], 0, len(b[MetadataLen:]))[i] == sl.GetByte(b[MetadataLen:], 0, len(b[MetadataLen:]), i) //@ unfold acc(sl.Bytes(b[MetadataLen:], 0, len(b)-MetadataLen), R56) //@ assert forall k int :: {&b[MetadataLen:][k]} 0 <= k && k < len(b)-MetadataLen ==> //@ &b[MetadataLen:][k] == &b[MetadataLen + k] @@ -188,8 +193,18 @@ func (p *Path) DecodeFromBytes(b []byte) (r error) { //@ b2 = b[MetadataLen:][2] //@ b3 = b[MetadataLen:][3] //@ hdr0 = binary.BigEndian.Uint32(b[MetadataLen:][:scion.MetaLen]) - //@ assert scion.RawBytesToMetaHdr(b[MetadataLen:]) == scion.DecodedFrom(hdr0) - //@ assert base0 == scion.RawBytesToBase(b[MetadataLen:]) + // bridge the exposed bytes to the sub-path view: GetByte and the direct byte + // reads coincide (same locations), so the view agrees with the bytes and + // binary.BigEndian.Uint32 over the bytes equals Uint32Spec over the view + //@ assert forall i int :: { sl.GetByte(b[MetadataLen:], 0, len(b[MetadataLen:]), i) } 0 <= i && i < scion.MetaLen ==> + //@ sl.GetByte(b[MetadataLen:], 0, len(b[MetadataLen:]), i) == b[MetadataLen:][i] + //@ assert forall i int :: { sl.View(b[MetadataLen:], 0, len(b[MetadataLen:]))[i] } 0 <= i && i < scion.MetaLen ==> + //@ sl.View(b[MetadataLen:], 0, len(b[MetadataLen:]))[i] == b[MetadataLen:][i] + //@ assert hdr0 == binary.BigEndian.Uint32Spec(sl.View(b[MetadataLen:], 0, len(b[MetadataLen:]))[0], + //@ sl.View(b[MetadataLen:], 0, len(b[MetadataLen:]))[1], sl.View(b[MetadataLen:], 0, len(b[MetadataLen:]))[2], + //@ sl.View(b[MetadataLen:], 0, len(b[MetadataLen:]))[3]) + //@ assert scion.RawBytesToMetaHdr(sl.View(b[MetadataLen:], 0, len(b[MetadataLen:]))) == scion.DecodedFrom(hdr0) + //@ assert base0 == scion.RawBytesToBase(sl.View(b[MetadataLen:], 0, len(b[MetadataLen:]))) //@ assert base0.PathMeta == scion.DecodedFrom(hdr0) //@ assert base0.NumINF == io.CombineSegLens(int(base0.PathMeta.SegLen[0]), //@ int(base0.PathMeta.SegLen[1]), int(base0.PathMeta.SegLen[2])).NumInfoFields() diff --git a/pkg/slayers/path/epic/epic_spec.gobra b/pkg/slayers/path/epic/epic_spec.gobra index bdf63195f..4c093a351 100644 --- a/pkg/slayers/path/epic/epic_spec.gobra +++ b/pkg/slayers/path/epic/epic_spec.gobra @@ -121,4 +121,49 @@ pure func (p *Path) IsValidResultOfDecoding(b []byte) (res bool) { p.ScionPath.Base.GetBase().WeaklyValid() } +// DecodedBaseMatchesView lifts the byte-level characterization of a +// successfully decoded EPIC path (as exposed by IsValidResultOfDecoding) +// to the view-based form required by (*SCION).EqAbsHeader: the base of the +// decoded scion sub-path equals the one obtained by decoding the metadata +// header located right after the EPIC metadata prefix in the view of b. +ghost +requires acc(p.Mem(b), R55) +requires acc(sl.Bytes(b, 0, len(b)), R55) +requires p.IsValidResultOfDecoding(b) +ensures acc(p.Mem(b), R55) +ensures acc(sl.Bytes(b, 0, len(b)), R55) +ensures MetadataLen + scion.MetaLen <= len(b) +ensures p.GetBase(b) == scion.RawBytesToBase(sl.View(b, 0, len(b))[MetadataLen:]) +decreases +func (p *Path) DecodedBaseMatchesView(ghost b []byte) { + // exposed by IsValidResultOfDecoding + assert MetadataLen + scion.MetaLen <= len(b) + // pin the elementwise characterization of the view of b, retaining a + // positive fraction so the predicate snapshot (and hence the view) stays + // fixed; we refer to sl.View(b, 0, len(b)) directly so that the term is + // syntactically the one appearing in the postcondition + sl.ViewElems(b, 0, len(b), R56) + assert forall i int :: { sl.View(b, 0, len(b))[MetadataLen + i] } 0 <= i && i < scion.MetaLen ==> + sl.View(b, 0, len(b))[MetadataLen + i] == sl.GetByte(b, 0, len(b), MetadataLen + i) + // expose the raw metadata-header bytes; the retained folded fraction keeps + // the snapshot pinned, so GetByte, View, and IsValidResultOfDecoding stay + // evaluable and agree with the bytes read below + unfold acc(sl.Bytes(b, 0, len(b)), R56) + assert forall k int :: { &b[MetadataLen:][k] } 0 <= k && k < len(b) - MetadataLen ==> + &b[MetadataLen:][k] == &b[MetadataLen + k] + assert forall k int :: { &b[MetadataLen:][:scion.MetaLen][k] } 0 <= k && k < scion.MetaLen ==> + &b[MetadataLen:][:scion.MetaLen][k] == &b[MetadataLen:][k] + assert forall i int :: { sl.GetByte(b, 0, len(b), MetadataLen + i) } 0 <= i && i < scion.MetaLen ==> + sl.GetByte(b, 0, len(b), MetadataLen + i) == b[MetadataLen + i] + assert forall i int :: { sl.View(b, 0, len(b))[MetadataLen + i] } 0 <= i && i < scion.MetaLen ==> + sl.View(b, 0, len(b))[MetadataLen + i] == b[MetadataLen + i] + // binary.BigEndian.Uint32 over the raw bytes equals Uint32Spec over the view + assert binary.BigEndian.Uint32(b[MetadataLen:][:scion.MetaLen]) == + binary.BigEndian.Uint32Spec(sl.View(b, 0, len(b))[MetadataLen], sl.View(b, 0, len(b))[MetadataLen + 1], + sl.View(b, 0, len(b))[MetadataLen + 2], sl.View(b, 0, len(b))[MetadataLen + 3]) + // hence the decoded metadata headers, and therefore the bases, coincide + assert scion.RawBytesToBase(sl.View(b, 0, len(b))[MetadataLen:]) == p.GetBase(b) + fold acc(sl.Bytes(b, 0, len(b)), R56) +} + (*Path) implements path.Path \ No newline at end of file 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 b74c6d61d..56b56cb61 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 } @@ -325,15 +330,16 @@ func (s *SCION) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeO // @ ensures res == nil ==> s.Mem(data) // @ ensures res == nil && CmnHdrLen <= len(data) && // @ typeOf(s.GetPath(data)) == *scion.Raw && -// @ path.Type(GetPathType(data)) != epic.PathType ==> +// @ path.Type(GetPathType(sl.View(data, 0, len(data)))) != epic.PathType ==> // @ s.EqAbsHeader(data) && s.ValidScionInitSpec(data) // @ ensures res == nil && CmnHdrLen <= len(data) && // @ typeOf(s.GetPath(data)) == *epic.Path && -// @ path.Type(GetPathType(data)) == epic.PathType ==> +// @ path.Type(GetPathType(sl.View(data, 0, len(data)))) == epic.PathType ==> // @ s.EqAbsHeader(data) && s.ValidScionInitSpec(data) // @ 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 { @@ -359,14 +365,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] @@ -378,7 +389,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) @@ -438,34 +451,40 @@ func (s *SCION) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) (res er s.Contents = data[:hdrBytes] s.Payload = data[hdrBytes:] // @ fold acc(s.Mem(data), R54) - // @ ghost if typeOf(s.GetPath(data)) == (*scion.Raw) && path.Type(GetPathType(data)) != epic.PathType { - // @ unfold acc(sl.Bytes(data, 0, len(data)), R56) - // @ unfold acc(sl.Bytes(data[offset : offset+pathLen], 0, len(data[offset : offset+pathLen])), R56) + // @ ghost if typeOf(s.GetPath(data)) == (*scion.Raw) && path.Type(GetPathType(sl.View(data, 0, len(data)))) != epic.PathType { + // @ 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) // @ } - // @ ghost if typeOf(s.GetPath(data)) == (*epic.Path) && path.Type(GetPathType(data)) == epic.PathType { - // @ unfold acc(sl.Bytes(data, 0, len(data)), R56) - // @ unfold acc(sl.Bytes(data[offset : offset+pathLen], 0, len(data[offset : offset+pathLen])), R56) + // @ ghost if typeOf(s.GetPath(data)) == (*epic.Path) && path.Type(GetPathType(sl.View(data, 0, len(data)))) == epic.PathType { + // @ 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] + // DecodedBaseMatchesView expresses the base of the scion sub-path as the + // metadata header located right after the EPIC metadata prefix, over the + // view of the whole sub-path bytes. The ViewOfSubslice above relates that + // view to the matching range of the whole-packet view, so the resulting + // equality is exactly what EqAbsHeader's EPIC branch demands. It is a pure + // value equality on the (shared) sub-path base, so it survives the unfolds + // below and can be consumed by the reveal. + // @ s.Path.(*epic.Path).DecodedBaseMatchesView(data[offset : offset+pathLen]) // @ unfold acc(s.Path.(*epic.Path).Mem(data[offset : offset+pathLen]), R55) // @ unfold acc(s.Path.(*epic.Path).ScionPath.Mem(data[offset : offset+pathLen][epic.MetadataLen:]), R55) // @ assert reveal s.EqAbsHeader(data) // @ assert reveal s.ValidScionInitSpec(data) // @ fold acc(s.Path.(*epic.Path).ScionPath.Mem(data[offset : offset+pathLen][epic.MetadataLen:]), R55) // @ fold acc(s.Path.(*epic.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 CmnHdrLen <= len(data) && typeOf(s.GetPath(data)) == *scion.Raw && - // @ path.Type(GetPathType(data)) != epic.PathType ==> + // @ path.Type(GetPathType(sl.View(data, 0, len(data)))) != epic.PathType ==> // @ s.EqAbsHeader(data) && s.ValidScionInitSpec(data) // @ assert CmnHdrLen <= len(data) && typeOf(s.GetPath(data)) == *epic.Path && - // @ path.Type(GetPathType(data)) == epic.PathType ==> + // @ path.Type(GetPathType(sl.View(data, 0, len(data)))) == epic.PathType ==> // @ s.EqAbsHeader(data) && s.ValidScionInitSpec(data) // @ assert reveal s.EqPathType(data) // @ fold acc(s.Mem(data), 1-R54) diff --git a/pkg/slayers/scion_spec.gobra b/pkg/slayers/scion_spec.gobra index 3bcf6a96f..bd01e44fb 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,43 +397,22 @@ 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) && (typeOf(s.Path) == (*scion.Raw) || typeOf(s.Path) == (*epic.Path)) && ((typeOf(s.Path) == (*epic.Path)) == - (path.Type(GetPathType(ub)) == epic.PathType)) && + (path.Type(GetPathType(v)) == epic.PathType)) && // The SCION path starts at the path offset, except for packets with // an EPIC path, where it is prefixed by the EPIC metadata. (typeOf(s.Path) == (*epic.Path) ? (unfolding s.Path.Mem(ub[low_:high]) in unfolding s.Path.(*epic.Path).ScionPath.Mem(ub[low_:high][epic.MetadataLen:]) 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][epic.MetadataLen:][k]} 0 <= k && k < high-low_-epic.MetadataLen ==> - &ub[low_:high][epic.MetadataLen:][k] == &ub[low_:high][epic.MetadataLen + k]) in - let _ := Asserting(forall k int :: {&ub[low_:high][epic.MetadataLen:][:scion.MetaLen][k]} 0 <= k && k < scion.MetaLen ==> - &ub[low_:high][epic.MetadataLen:][:scion.MetaLen][k] == &ub[low_:high][epic.MetadataLen:][k]) in - let metaHdr := scion.DecodedFrom(binary.BigEndian.Uint32(ub[low_:high][epic.MetadataLen:][: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.(*epic.Path).ScionPath.Base.GetBase() == - scion.Base{metaHdr, segs.NumInfoFields(), segs.TotalHops()}) : + scion.RawBytesToBase(v[low_ + epic.MetadataLen : high])) : (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`. @@ -472,19 +435,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 := GetScionPathOffset(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 @@ -498,134 +457,95 @@ 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 -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 GetPathType(raw) == GetPathType(raw[:idx]) +requires CmnHdrLen <= idx && idx <= len(raw) +ensures GetPathType(raw) == GetPathType(raw[:idx]) decreases -func GetPathTypeSubslice(raw []byte, idx int) { - unfold acc(sl.Bytes(raw, 0, len(raw)), R56) - unfold acc(sl.Bytes(raw[:idx], 0, idx), R56) - fold acc(sl.Bytes(raw, 0, len(raw)), R56) - fold acc(sl.Bytes(raw[:idx], 0, idx), R56) +func GetPathTypeSubslice(raw seq[byte], idx int) { + assert raw[:idx][8] == raw[8] } 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)) +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 } +// Computes the address offset from a view bounded by `length`. Since the +// address offset is fully determined by the address-type nibbles at index 9, +// this coincides with `GetAddressOffset(raw)`. ghost -requires sl.Bytes(ub, 0, length) -requires CmnHdrLen <= length +requires CmnHdrLen <= length && length <= len(raw) 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 - CmnHdrLen + 2*addr.IABytes + dstAddrLen + srcAddrLen +pure func GetAddressOffsetWithinLength(raw seq[byte], length int) int { + return GetAddressOffset(raw) } // Returns the offset of the SCION path within the packet. This matches the // path offset, except for packets with an EPIC path, where the SCION path // is prefixed by the EPIC metadata. ghost -requires sl.Bytes(ub, 0, len(ub)) -requires CmnHdrLen <= len(ub) +requires CmnHdrLen <= len(raw) decreases -pure func GetScionPathOffset(ub []byte) int { - return GetAddressOffset(ub) + - (path.Type(GetPathType(ub)) == epic.PathType ? epic.MetadataLen : 0) +pure func GetScionPathOffset(raw seq[byte]) int { + return GetAddressOffset(raw) + + (path.Type(GetPathType(raw)) == epic.PathType ? epic.MetadataLen : 0) } ghost -requires sl.Bytes(ub, 0, len(ub)) -requires CmnHdrLen <= len(ub) +requires CmnHdrLen <= len(raw) decreases -pure func GetLength(ub []byte) int { - return GetLengthWithinLength(ub, len(ub)) +pure func GetLength(raw seq[byte]) int { + return int(raw[5]) * LineLen } 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 GetPathType(raw seq[byte]) int { + return int(raw[8]) } ghost -requires sl.Bytes(ub, 0, len(ub)) -requires CmnHdrLen <= len(ub) -decreases -pure func GetPathType(ub []byte) int { - return unfolding sl.Bytes(ub, 0, len(ub)) in - int(ub[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 @@ -634,15 +554,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 7803ba3c7..fda75c5aa 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}() @@ -1568,10 +1568,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) @@ -1682,12 +1682,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() @@ -1700,7 +1700,7 @@ func (p *scionPacketProcessor) processPkt(rawPkt []byte, // @ } // @ assert sl.Bytes(p.rawPkt, 0, len(p.rawPkt)) // @ assert reveal p.scionLayer.EqPathType(p.rawPkt) - // @ assert path.Type(slayers.GetPathType(p.rawPkt)) != epic.PathType + // @ assert path.Type(slayers.GetPathType(sl.View(p.rawPkt, 0, len(p.rawPkt)))) != epic.PathType v1, v2 /*@ , addrAliasesPkt, newAbsPkt @*/ := p.processSCION( /*@ p.rawPkt, ub == nil, llStart, llEnd, ioLock, ioSharedArg, dp @*/ ) // @ ResetDecodingLayers(&p.scionLayer, &p.hbhLayer, &p.e2eLayer, ubScionLayer, ubHbhLayer, ubE2eLayer, v2 == nil, hasHbhLayer, hasE2eLayer) // @ fold p.sInit() @@ -1715,9 +1715,9 @@ func (p *scionPacketProcessor) processPkt(rawPkt []byte, // @ } // @ 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)))) // @ assert sl.Bytes(p.rawPkt, 0, len(p.rawPkt)) - // @ assert path.Type(slayers.GetPathType(p.rawPkt)) == epic.PathType + // @ assert path.Type(slayers.GetPathType(sl.View(p.rawPkt, 0, len(p.rawPkt)))) == epic.PathType // @ assert unfolding acc(p.scionLayer.Mem(p.rawPkt), R56) in slayers.CmnHdrLen <= len(p.rawPkt) // @ assert typeOf(p.scionLayer.GetPath(p.rawPkt)) == *epic.Path ==> // @ p.scionLayer.EqAbsHeader(p.rawPkt) && p.scionLayer.ValidScionInitSpec(p.rawPkt) @@ -1897,12 +1897,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{}) @@ -1974,19 +1974,19 @@ func (p *scionPacketProcessor) processSCION( /*@ ghost ub []byte, ghost llIsNil // @ 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))) // @ requires p.d.DpAgreesWithSpec(dp) // @ requires dp.Valid() // @ requires (typeOf(p.scionLayer.GetPath(ub)) == *epic.Path) ==> // @ p.scionLayer.EqAbsHeader(ub) && p.scionLayer.ValidScionInitSpec(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{}) @@ -2176,7 +2176,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, @@ -2266,13 +2266,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) { @@ -2280,12 +2280,27 @@ func (p *scionPacketProcessor) parsePath( /*@ ghost ub []byte @*/ ) (respr proce // @ assert unfolding acc(p.scionLayer.Mem(ub), R56) in slayers.CmnHdrLen <= len(ub) // @ assert reveal p.scionLayer.EqAbsHeader(ub) // @ assert (typeOf(p.scionLayer.GetPath(ub)) == *epic.Path) == - // @ (path.Type(slayers.GetPathType(ub)) == epic.PathType) + // @ (path.Type(slayers.GetPathType(sl.View(ub, 0, len(ub)))) == epic.PathType) // @ ghost startP := p.scionLayer.PathStartIdx(ub) // @ ghost endP := p.scionLayer.PathEndIdx(ub) // @ ghost ubPath := ub[startP:endP] // @ ghost startScionP := p.scionLayer.PathScionStartIdx(ub) // @ ghost endScionP := p.scionLayer.PathScionEndIdx(ub) + // the scion sub-path slice below needs its bounds. 0 <= startScionP and + // endScionP <= len(ub) follow from the SCION Mem; startScionP <= endScionP + // holds for a raw path directly (startScionP == startP <= endP), and for + // an EPIC path because epic.Path.Mem requires epic.MetadataLen <= len(ubPath), + // i.e. startP + epic.MetadataLen <= endP. The byte-based EqAbsHeader used + // to surface this; the view-based one does not, so derive it explicitly. + // @ ghost if typeOf(p.scionLayer.GetPath(ub)) == *epic.Path { + // @ assert unfolding acc(p.scionLayer.Mem(ub), R56) in + // @ unfolding acc(p.scionLayer.Path.Mem(ubPath), R56) in + // @ epic.MetadataLen <= len(ubPath) + // @ assert len(ubPath) == endP - startP + // @ assert startScionP == startP + epic.MetadataLen + // @ assert endScionP == endP + // @ } + // @ assert 0 <= startScionP && startScionP <= endScionP && endScionP <= len(ub) // @ ghost ubScionPath := ub[startScionP:endScionP] // @ unfold acc(p.scionLayer.Mem(ub), R6) // @ defer fold acc(p.scionLayer.Mem(ub), R6) @@ -2337,15 +2352,15 @@ func (p *scionPacketProcessor) parsePath( /*@ ghost ub []byte @*/ ) (respr proce // @ p.EstablishEqAbsHeader(ub, startScionP, endScionP) // @ p.path.EstablishValidPktMetaHdr(ubScionPath) // @ p.SubSliceAbsPktToAbsPkt(ub, startScionP, endScionP) - // @ absPktFutureLemma(ub) + // @ absPktFutureLemma(sl.View(ub, 0, len(ub))) // @ p.path.DecodingLemma(ubScionPath, p.infoField, p.hopField) - // @ assert reveal p.path.EqAbsInfoField(p.path.absPkt(ubScionPath), + // @ assert reveal p.path.EqAbsInfoField(p.path.absPkt(sl.View(ubScionPath, 0, len(ubScionPath))), // @ p.infoField.ToAbsInfoField()) - // @ assert reveal p.path.EqAbsHopField(p.path.absPkt(ubScionPath), + // @ assert reveal p.path.EqAbsHopField(p.path.absPkt(sl.View(ubScionPath, 0, len(ubScionPath))), // @ 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 } @@ -2359,8 +2374,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 ==> @@ -2383,12 +2398,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). @@ -2433,7 +2448,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 } @@ -2476,17 +2491,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 @@ -2505,11 +2520,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)) @@ -2546,22 +2561,22 @@ 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) { // @ assert unfolding acc(p.scionLayer.Mem(ubScionL), R56) in slayers.CmnHdrLen <= len(ubScionL) // @ assert reveal p.scionLayer.EqAbsHeader(ubScionL) // @ assert (typeOf(p.scionLayer.GetPath(ubScionL)) == *epic.Path) == - // @ (path.Type(slayers.GetPathType(ubScionL)) == epic.PathType) + // @ (path.Type(slayers.GetPathType(sl.View(ubScionL, 0, len(ubScionL)))) == epic.PathType) // @ unfold acc(p.scionLayer.Mem(ubScionL), R20) // @ defer fold acc(p.scionLayer.Mem(ubScionL), R20) // @ ghost startP := p.scionLayer.PathStartIdx(ubScionL) @@ -2578,7 +2593,8 @@ func (p *scionPacketProcessor) validateSrcDstIA( /*@ ghost ubScionL []byte, ghos // @ } // @ sl.SplitRange_Bytes(ubScionL, startScionP, endScionP, R50) // @ p.AbsPktToSubSliceAbsPkt(ubScionL, startScionP, endScionP) - // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ubScionL, startScionP) + // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ubScionL, sl.View(ubScionL, 0, len(ubScionL)), startScionP) + // @ assert sl.View(ubScionL, 0, len(ubScionL))[:startScionP] == sl.View(ubScionL, 0, startScionP) // @ unfold acc(p.scionLayer.HeaderMem(ubScionL[slayers.CmnHdrLen:]), R20) // @ defer fold acc(p.scionLayer.HeaderMem(ubScionL[slayers.CmnHdrLen:]), R20) // @ p.d.getLocalIA() @@ -2604,12 +2620,13 @@ func (p *scionPacketProcessor) validateSrcDstIA( /*@ ghost ubScionL []byte, ghos return p.invalidSrcIA( /*@ ubScionL, ubLL, startLL, endLL @*/ ) } if p.path.IsLastHop( /*@ ubScionPath @*/ ) != dstIsLocal { - // @ ghost sl.CombineRange_Bytes(ubScionL, startScionP, endScionP, R50) + // @ ghost sl.CombineRangeWithViews_Bytes(ubScionL, startScionP, endScionP, R50, sl.View(ubScionL, 0, startScionP), sl.View(ubScionL[startScionP:endScionP], 0, (endScionP)-(startScionP)), sl.View(ubScionL, endScionP, len(ubScionL))) return p.invalidDstIA( /*@ ubScionL, ubLL, startLL, endLL @*/ ) } // @ ghost if(p.path.IsLastHopSpec(ubScionPath)) { // @ p.path.LastHopLemma(ubScionPath) - // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ubScionL, startScionP) + // @ assert sl.View(ubScionL, 0, len(ubScionL))[:startScionP] == sl.View(ubScionL, 0, startScionP) + // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ubScionL, sl.View(ubScionL, 0, len(ubScionL)), startScionP) // @ p.SubSliceAbsPktToAbsPkt(ubScionL, startScionP, endScionP) // @ } } @@ -2655,7 +2672,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, @@ -2672,7 +2689,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 } @@ -2705,7 +2722,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, @@ -2722,7 +2739,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 } @@ -2849,31 +2866,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() @@ -2899,7 +2916,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 } @@ -2939,7 +2956,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 } @@ -2970,7 +2987,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 } @@ -2984,12 +3001,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)) @@ -2999,14 +3016,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) @@ -3020,7 +3037,7 @@ func (p *scionPacketProcessor) updateNonConsDirIngressSegID( /*@ ghost ub []byte // @ assert unfolding acc(p.scionLayer.Mem(ub), R56) in slayers.CmnHdrLen <= len(ub) // @ assert reveal p.scionLayer.EqAbsHeader(ub) // @ assert (typeOf(p.scionLayer.GetPath(ub)) == *epic.Path) == - // @ (path.Type(slayers.GetPathType(ub)) == epic.PathType) + // @ (path.Type(slayers.GetPathType(sl.View(ub, 0, len(ub)))) == epic.PathType) // @ unfold acc(p.scionLayer.Mem(ub), R20) // @ defer fold acc(p.scionLayer.Mem(ub), R20) // @ ghost if typeOf(p.scionLayer.Path) == *epic.Path { @@ -3033,8 +3050,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) @@ -3045,33 +3062,44 @@ func (p *scionPacketProcessor) updateNonConsDirIngressSegID( /*@ ghost ub []byte // @ sl.SplitRange_Bytes(ub, startScionP, endScionP, HalfPerm) // @ sl.SplitByIndex_Bytes(ub, 0, startScionP, slayers.CmnHdrLen, R54) // @ sl.Reslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) - // @ slayers.IsSupportedPktSubslice(ub, slayers.CmnHdrLen) - // @ slayers.GetPathTypeSubslice(ub, slayers.CmnHdrLen) + // @ slayers.IsSupportedPktSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) + // @ slayers.GetPathTypeSubslice(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, startScionP) + // @ assert sl.View(ub, 0, len(ub))[:startScionP] == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:slayers.CmnHdrLen] == vHdrPre[:slayers.CmnHdrLen] // @ p.AbsPktToSubSliceAbsPkt(ub, startScionP, endScionP) - // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ub, startScionP) + // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ub, sl.View(ub, 0, len(ub)), startScionP) + // @ assert sl.View(ub, 0, len(ub))[:startScionP] == sl.View(ub, 0, startScionP) // @ sl.SplitRange_Bytes(ub, startScionP, endScionP, HalfPerm) if err := p.path.SetInfoField(p.infoField, int( /*@ unfolding acc(p.path.Mem(ubScionPath), R45) in (unfolding acc(p.path.Base.Mem(), R50) in @*/ p.path.PathMeta.CurrINF) /*@ ) , ubScionPath, @*/); err != nil { // @ sl.Unslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) // @ sl.CombineAtIndex_Bytes(ub, 0, startScionP, slayers.CmnHdrLen, R54) - // @ ghost sl.CombineRange_Bytes(ub, startScionP, endScionP, writePerm) + // @ ghost sl.CombineRangeWithViews_Bytes(ub, startScionP, endScionP, writePerm, sl.View(ub, 0, startScionP), sl.View(ub[startScionP:endScionP], 0, (endScionP)-(startScionP)), sl.View(ub, endScionP, len(ub))) return serrors.WrapStr("update info field", err) } - // @ ghost sl.CombineRange_Bytes(ub, startScionP, endScionP, HalfPerm) - // @ slayers.IsSupportedPktSubslice(ub, slayers.CmnHdrLen) - // @ slayers.GetPathTypeSubslice(ub, slayers.CmnHdrLen) + // @ ghost sl.CombineRangeWithViews_Bytes(ub, startScionP, endScionP, HalfPerm, sl.View(ub, 0, startScionP), sl.View(ub[startScionP:endScionP], 0, (endScionP)-(startScionP)), sl.View(ub, endScionP, len(ub))) + // @ assert sl.View(ub, 0, startScionP) == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:startScionP] == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:slayers.CmnHdrLen] == vHdrPre[:slayers.CmnHdrLen] + // @ slayers.IsSupportedPktSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) + // @ slayers.GetPathTypeSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) // @ sl.Unslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) // @ sl.CombineAtIndex_Bytes(ub, 0, startScionP, slayers.CmnHdrLen, R54) - // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ub, startScionP) + // @ assert sl.View(ub, 0, len(ub))[:startScionP] == sl.View(ub, 0, startScionP) + // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ub, sl.View(ub, 0, len(ub)), startScionP) // @ p.SubSliceAbsPktToAbsPkt(ub, startScionP, endScionP) - // @ ghost sl.CombineRange_Bytes(ub, startScionP, endScionP, HalfPerm) - // @ absPktFutureLemma(ub) - // @ assert absPkt(ub).CurrSeg.UInfo == + // @ ghost sl.CombineRangeWithViews_Bytes(ub, startScionP, endScionP, HalfPerm, sl.View(ub, 0, startScionP), sl.View(ub[startScionP:endScionP], 0, (endScionP)-(startScionP)), sl.View(ub, endScionP, 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 } @@ -3161,22 +3189,22 @@ func (p *scionPacketProcessor) currentHopPointer( /*@ ghost ubScionL []byte @*/ // @ respr === processResult{} // @ ensures reserr == nil ==> sl.Bytes(p.cachedMac, 0, len(p.cachedMac)) // 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) @@ -3213,7 +3241,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 } @@ -3241,8 +3269,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 @@ -3270,12 +3298,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, @@ -3294,7 +3322,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: @@ -3311,10 +3339,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)) @@ -3326,10 +3354,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) @@ -3343,7 +3371,7 @@ func (p *scionPacketProcessor) processEgress( /*@ ghost ub []byte @*/ ) (reserr // @ assert unfolding acc(p.scionLayer.Mem(ub), R56) in slayers.CmnHdrLen <= len(ub) // @ assert reveal p.scionLayer.EqAbsHeader(ub) // @ assert (typeOf(p.scionLayer.GetPath(ub)) == *epic.Path) == - // @ (path.Type(slayers.GetPathType(ub)) == epic.PathType) + // @ (path.Type(slayers.GetPathType(sl.View(ub, 0, len(ub)))) == epic.PathType) // @ unfold acc(p.scionLayer.Mem(ub), 1-R55) // @ ghost if typeOf(p.scionLayer.Path) == *epic.Path { // @ unfold acc(p.scionLayer.Path.Mem(ubPath), 1-R55) @@ -3353,14 +3381,21 @@ func (p *scionPacketProcessor) processEgress( /*@ ghost ub []byte @*/ ) (reserr // @ sl.SplitRange_Bytes(ub, startScionP, endScionP, HalfPerm) // @ sl.SplitByIndex_Bytes(ub, 0, startScionP, slayers.CmnHdrLen, R54) // @ sl.Reslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) - // @ slayers.IsSupportedPktSubslice(ub, slayers.CmnHdrLen) - // @ slayers.GetPathTypeSubslice(ub, slayers.CmnHdrLen) + // @ slayers.IsSupportedPktSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) + // @ slayers.GetPathTypeSubslice(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, startScionP) + // @ assert sl.View(ub, 0, len(ub))[:startScionP] == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:slayers.CmnHdrLen] == vHdrPre[:slayers.CmnHdrLen] // @ p.AbsPktToSubSliceAbsPkt(ub, startScionP, endScionP) - // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ub, startScionP) - // @ reveal p.EqAbsInfoField(absPkt(ub)) - // @ reveal p.EqAbsHopField(absPkt(ub)) + // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ub, sl.View(ub, 0, len(ub)), startScionP) + // @ assert sl.View(ub, 0, len(ub))[:startScionP] == sl.View(ub, 0, startScionP) + // @ reveal p.EqAbsInfoField(absPkt(sl.View(ub, 0, len(ub)))) + // @ reveal p.EqAbsHopField(absPkt(sl.View(ub, 0, len(ub)))) // @ sl.SplitRange_Bytes(ub, startScionP, endScionP, HalfPerm) - // @ reveal p.scionLayer.ValidHeaderOffset(ub, startScionP) + // @ reveal p.scionLayer.ValidHeaderOffset(ub, sl.View(ub, 0, startScionP)) // @ unfold acc(p.scionLayer.Mem(ub), R55) // @ ghost if typeOf(p.scionLayer.Path) == *epic.Path { // @ unfold acc(p.scionLayer.Path.Mem(ubPath), R55) @@ -3400,17 +3435,21 @@ func (p *scionPacketProcessor) processEgress( /*@ ghost ub []byte @*/ ) (reserr // @ fold acc(p.scionLayer.Path.Mem(ubPath), R55) // @ } // @ fold acc(p.scionLayer.Mem(ub), R55) - // @ assert reveal p.scionLayer.ValidHeaderOffset(ub, startScionP) - // @ ghost sl.CombineRange_Bytes(ub, startScionP, endScionP, HalfPerm) - // @ slayers.IsSupportedPktSubslice(ub, slayers.CmnHdrLen) - // @ slayers.GetPathTypeSubslice(ub, slayers.CmnHdrLen) + // @ assert reveal p.scionLayer.ValidHeaderOffset(ub, sl.View(ub, 0, startScionP)) + // @ ghost sl.CombineRangeWithViews_Bytes(ub, startScionP, endScionP, HalfPerm, sl.View(ub, 0, startScionP), sl.View(ub[startScionP:endScionP], 0, (endScionP)-(startScionP)), sl.View(ub, endScionP, len(ub))) + // @ assert sl.View(ub, 0, startScionP) == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:startScionP] == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:slayers.CmnHdrLen] == vHdrPre[:slayers.CmnHdrLen] + // @ slayers.IsSupportedPktSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) + // @ slayers.GetPathTypeSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) // @ sl.Unslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) // @ sl.CombineAtIndex_Bytes(ub, 0, startScionP, slayers.CmnHdrLen, R54) - // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ub, startScionP) + // @ assert sl.View(ub, 0, len(ub))[:startScionP] == sl.View(ub, 0, startScionP) + // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ub, sl.View(ub, 0, len(ub)), startScionP) // @ p.SubSliceAbsPktToAbsPkt(ub, startScionP, endScionP) - // @ ghost sl.CombineRange_Bytes(ub, startScionP, endScionP, HalfPerm) - // @ absPktFutureLemma(ub) - // @ assert absPkt(ub) == reveal AbsProcessEgress(old(absPkt(ub))) + // @ ghost sl.CombineRangeWithViews_Bytes(ub, startScionP, endScionP, HalfPerm, sl.View(ub, 0, startScionP), sl.View(ub[startScionP:endScionP], 0, (endScionP)-(startScionP)), sl.View(ub, endScionP, 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))))) // @ ghost if typeOf(p.scionLayer.Path) == *epic.Path { // @ fold acc(p.scionLayer.Path.Mem(ubPath), 1-R55) // @ } @@ -3426,7 +3465,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 // @ let ubScionPath := p.scionLayer.UBScionPath(ub) in @@ -3449,17 +3488,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 ==> p.path === p.scionLayer.GetScionPath(ub) // @ ensures reserr == nil ==> // @ let ubPath := p.scionLayer.UBPath(ub) in @@ -3485,7 +3524,7 @@ func (p *scionPacketProcessor) doXover( /*@ ghost ub []byte, ghost currBase scio // @ assert unfolding acc(p.scionLayer.Mem(ub), R56) in slayers.CmnHdrLen <= len(ub) // @ assert reveal p.scionLayer.EqAbsHeader(ub) // @ assert (typeOf(p.scionLayer.GetPath(ub)) == *epic.Path) == - // @ (path.Type(slayers.GetPathType(ub)) == epic.PathType) + // @ (path.Type(slayers.GetPathType(sl.View(ub, 0, len(ub)))) == epic.PathType) // @ unfold acc(p.scionLayer.Mem(ub), 1-R55) // @ ghost if typeOf(p.scionLayer.Path) == *epic.Path { // @ unfold acc(p.scionLayer.Path.Mem(ubPath), 1-R55) @@ -3495,18 +3534,25 @@ func (p *scionPacketProcessor) doXover( /*@ ghost ub []byte, ghost currBase scio // @ sl.SplitRange_Bytes(ub, startScionP, endScionP, HalfPerm) // @ sl.SplitByIndex_Bytes(ub, 0, startScionP, slayers.CmnHdrLen, R54) // @ sl.Reslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) - // @ slayers.IsSupportedPktSubslice(ub, slayers.CmnHdrLen) - // @ slayers.GetPathTypeSubslice(ub, slayers.CmnHdrLen) + // @ slayers.IsSupportedPktSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) + // @ slayers.GetPathTypeSubslice(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, startScionP) + // @ assert sl.View(ub, 0, len(ub))[:startScionP] == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:slayers.CmnHdrLen] == vHdrPre[:slayers.CmnHdrLen] // @ assert p.path === p.scionLayer.GetScionPath(ub) // @ p.AbsPktToSubSliceAbsPkt(ub, startScionP, endScionP) // @ assert p.path === p.scionLayer.GetScionPath(ub) - // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ub, startScionP) - // @ ghost preAbsPkt := p.path.absPkt(ubScionPath) + // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ub, sl.View(ub, 0, len(ub)), startScionP) + // @ assert sl.View(ub, 0, len(ub))[:startScionP] == sl.View(ub, 0, startScionP) + // @ ghost preAbsPkt := p.path.absPkt(sl.View(ubScionPath, 0, len(ubScionPath))) // @ p.path.XoverLemma(ubScionPath) - // @ 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, startScionP, endScionP, HalfPerm) - // @ reveal p.scionLayer.ValidHeaderOffset(ub, startScionP) + // @ reveal p.scionLayer.ValidHeaderOffset(ub, sl.View(ub, 0, startScionP)) // @ unfold acc(p.scionLayer.Mem(ub), R55) // @ ghost if typeOf(p.scionLayer.Path) == *epic.Path { // @ unfold acc(p.scionLayer.Path.Mem(ubPath), R55) @@ -3526,29 +3572,33 @@ func (p *scionPacketProcessor) doXover( /*@ ghost ub []byte, ghost currBase scio return processResult{}, serrors.WrapStr("incrementing path", err) } // @ assert p.path.GetBase(ubScionPath) == nextBase - // @ assert p.path.absPkt(ubScionPath) == scion.AbsXover(preAbsPkt) + // @ assert p.path.absPkt(sl.View(ubScionPath, 0, len(ubScionPath))) == scion.AbsXover(preAbsPkt) // @ ghost if typeOf(p.scionLayer.Path) == *epic.Path { // @ fold acc(p.scionLayer.Path.Mem(ubPath), R55) // @ } // @ fold acc(p.scionLayer.Mem(ub), R55) - // @ assert reveal p.scionLayer.ValidHeaderOffset(ub, startScionP) - // @ ghost sl.CombineRange_Bytes(ub, startScionP, endScionP, HalfPerm) - // @ slayers.IsSupportedPktSubslice(ub, slayers.CmnHdrLen) - // @ slayers.GetPathTypeSubslice(ub, slayers.CmnHdrLen) + // @ assert reveal p.scionLayer.ValidHeaderOffset(ub, sl.View(ub, 0, startScionP)) + // @ ghost sl.CombineRangeWithViews_Bytes(ub, startScionP, endScionP, HalfPerm, sl.View(ub, 0, startScionP), sl.View(ub[startScionP:endScionP], 0, (endScionP)-(startScionP)), sl.View(ub, endScionP, len(ub))) + // @ assert sl.View(ub, 0, startScionP) == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:startScionP] == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:slayers.CmnHdrLen] == vHdrPre[:slayers.CmnHdrLen] + // @ slayers.IsSupportedPktSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) + // @ slayers.GetPathTypeSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) // @ sl.Unslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) // @ sl.CombineAtIndex_Bytes(ub, 0, startScionP, slayers.CmnHdrLen, R54) // @ assert p.path === p.scionLayer.GetScionPath(ub) - // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ub, startScionP) - // @ assert p.scionLayer.ValidHeaderOffset(ub, len(ub)) + // @ assert sl.View(ub, 0, len(ub))[:startScionP] == sl.View(ub, 0, startScionP) + // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ub, sl.View(ub, 0, len(ub)), startScionP) + // @ assert p.scionLayer.ValidHeaderOffset(ub, sl.View(ub, 0, len(ub))) // @ assert p.path === p.scionLayer.GetScionPath(ub) // @ p.SubSliceAbsPktToAbsPkt(ub, startScionP, endScionP) - // @ assert p.scionLayer.ValidHeaderOffset(ub, len(ub)) + // @ assert p.scionLayer.ValidHeaderOffset(ub, sl.View(ub, 0, len(ub))) // @ assert p.path === p.scionLayer.GetScionPath(ub) // @ assert p.path.GetBase(ubScionPath) == 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.GetScionPath(ub) // @ assert p.path.GetBase(ubScionPath) == nextBase var err error @@ -3583,13 +3633,13 @@ func (p *scionPacketProcessor) doXover( /*@ ghost ub []byte, ghost currBase scio } // @ assert p.path.GetBase(ubScionPath) == nextBase // @ p.SubSliceAbsPktToAbsPkt(ub, startScionP, endScionP) - // @ ghost sl.CombineRange_Bytes(ub, startScionP, endScionP, HalfPerm/2) - // @ absPktFutureLemma(ub) + // @ ghost sl.CombineRangeWithViews_Bytes(ub, startScionP, endScionP, HalfPerm/2, sl.View(ub, 0, startScionP), sl.View(ub[startScionP:endScionP], 0, (endScionP)-(startScionP)), sl.View(ub, endScionP, len(ub))) + // @ absPktFutureLemma(sl.View(ub, 0, len(ub))) // @ p.path.DecodingLemma(ubScionPath, p.infoField, p.hopField) - // @ assert reveal p.path.EqAbsInfoField(p.path.absPkt(ubScionPath), p.infoField.ToAbsInfoField()) - // @ assert reveal p.path.EqAbsHopField(p.path.absPkt(ubScionPath), 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(ubScionPath, 0, len(ubScionPath))), p.infoField.ToAbsInfoField()) + // @ assert reveal p.path.EqAbsHopField(p.path.absPkt(sl.View(ubScionPath, 0, len(ubScionPath))), 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, startScionP, endScionP, HalfPerm/2) // @ ghost if typeOf(p.scionLayer.Path) == *epic.Path { // @ fold acc(p.scionLayer.Path.Mem(ubPath), 1-R55) @@ -3666,10 +3716,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 ==> @@ -3692,11 +3742,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, @@ -3704,7 +3754,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), _) } @@ -3728,7 +3778,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 } @@ -3776,24 +3826,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) @@ -3805,7 +3855,7 @@ func (p *scionPacketProcessor) handleIngressRouterAlert( /*@ ghost ub []byte, gh // @ assert unfolding acc(p.scionLayer.Mem(ub), R56) in slayers.CmnHdrLen <= len(ub) // @ assert reveal p.scionLayer.EqAbsHeader(ub) // @ assert (typeOf(p.scionLayer.GetPath(ub)) == *epic.Path) == - // @ (path.Type(slayers.GetPathType(ub)) == epic.PathType) + // @ (path.Type(slayers.GetPathType(sl.View(ub, 0, len(ub)))) == epic.PathType) if p.ingressID == 0 { // @ fold p.d.validResult(processResult{}, false) return processResult{}, nil @@ -3828,29 +3878,40 @@ func (p *scionPacketProcessor) handleIngressRouterAlert( /*@ ghost ub []byte, gh // @ sl.SplitRange_Bytes(ub, startScionP, endScionP, HalfPerm) // @ sl.SplitByIndex_Bytes(ub, 0, startScionP, slayers.CmnHdrLen, R54) // @ sl.Reslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) - // @ slayers.IsSupportedPktSubslice(ub, slayers.CmnHdrLen) - // @ slayers.GetPathTypeSubslice(ub, slayers.CmnHdrLen) + // @ slayers.IsSupportedPktSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) + // @ slayers.GetPathTypeSubslice(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, startScionP) + // @ assert sl.View(ub, 0, len(ub))[:startScionP] == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:slayers.CmnHdrLen] == vHdrPre[:slayers.CmnHdrLen] // @ p.AbsPktToSubSliceAbsPkt(ub, startScionP, endScionP) - // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ub, startScionP) + // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ub, sl.View(ub, 0, len(ub)), startScionP) + // @ assert sl.View(ub, 0, len(ub))[:startScionP] == sl.View(ub, 0, startScionP) // @ sl.SplitRange_Bytes(ub, startScionP, endScionP, HalfPerm) if err := p.path.SetHopField(p.hopField, int( /*@ unfolding acc(p.path.Mem(ubScionPath), R50) in (unfolding acc(p.path.Base.Mem(), R55) in @*/ p.path.PathMeta.CurrHF /*@ ) @*/) /*@ , ubScionPath @*/); err != nil { // @ sl.Unslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) // @ sl.CombineAtIndex_Bytes(ub, 0, startScionP, slayers.CmnHdrLen, R54) - // @ sl.CombineRange_Bytes(ub, startScionP, endScionP, writePerm) + // @ sl.CombineRangeWithViews_Bytes(ub, startScionP, endScionP, writePerm, sl.View(ub, 0, startScionP), sl.View(ub[startScionP:endScionP], 0, (endScionP)-(startScionP)), sl.View(ub, endScionP, len(ub))) // @ ghost if typeOf(p.scionLayer.Path) == *epic.Path { fold acc(p.scionLayer.Path.Mem(ubPath), R20) } // @ 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, startScionP, endScionP, HalfPerm) - // @ slayers.IsSupportedPktSubslice(ub, slayers.CmnHdrLen) - // @ slayers.GetPathTypeSubslice(ub, slayers.CmnHdrLen) + // @ sl.CombineRangeWithViews_Bytes(ub, startScionP, endScionP, HalfPerm, sl.View(ub, 0, startScionP), sl.View(ub[startScionP:endScionP], 0, (endScionP)-(startScionP)), sl.View(ub, endScionP, len(ub))) + // @ assert sl.View(ub, 0, startScionP) == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:startScionP] == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:slayers.CmnHdrLen] == vHdrPre[:slayers.CmnHdrLen] + // @ slayers.IsSupportedPktSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) + // @ slayers.GetPathTypeSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) // @ sl.Unslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) // @ sl.CombineAtIndex_Bytes(ub, 0, startScionP, slayers.CmnHdrLen, R54) - // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ub, startScionP) + // @ assert sl.View(ub, 0, len(ub))[:startScionP] == sl.View(ub, 0, startScionP) + // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ub, sl.View(ub, 0, len(ub)), startScionP) // @ p.SubSliceAbsPktToAbsPkt(ub, startScionP, endScionP) - // @ 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, startScionP, endScionP, HalfPerm) @@ -3908,22 +3969,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) @@ -3936,13 +3997,13 @@ func (p *scionPacketProcessor) handleEgressRouterAlert( /*@ ghost ub []byte, gho // @ assert unfolding acc(p.scionLayer.Mem(ub), R56) in slayers.CmnHdrLen <= len(ub) // @ assert reveal p.scionLayer.EqAbsHeader(ub) // @ assert (typeOf(p.scionLayer.GetPath(ub)) == *epic.Path) == - // @ (path.Type(slayers.GetPathType(ub)) == epic.PathType) + // @ (path.Type(slayers.GetPathType(sl.View(ub, 0, len(ub)))) == epic.PathType) alert := p.egressRouterAlertFlag() if !*alert { // @ 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 { @@ -3962,30 +4023,41 @@ func (p *scionPacketProcessor) handleEgressRouterAlert( /*@ ghost ub []byte, gho // @ sl.SplitRange_Bytes(ub, startScionP, endScionP, HalfPerm) // @ sl.SplitByIndex_Bytes(ub, 0, startScionP, slayers.CmnHdrLen, R54) // @ sl.Reslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) - // @ slayers.IsSupportedPktSubslice(ub, slayers.CmnHdrLen) - // @ slayers.GetPathTypeSubslice(ub, slayers.CmnHdrLen) + // @ slayers.IsSupportedPktSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) + // @ slayers.GetPathTypeSubslice(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, startScionP) + // @ assert sl.View(ub, 0, len(ub))[:startScionP] == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:slayers.CmnHdrLen] == vHdrPre[:slayers.CmnHdrLen] // @ p.AbsPktToSubSliceAbsPkt(ub, startScionP, endScionP) - // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ub, startScionP) + // @ p.scionLayer.ValidHeaderOffsetToSubSliceLemma(ub, sl.View(ub, 0, len(ub)), startScionP) + // @ assert sl.View(ub, 0, len(ub))[:startScionP] == sl.View(ub, 0, startScionP) // @ sl.SplitRange_Bytes(ub, startScionP, endScionP, HalfPerm) if err := p.path.SetHopField(p.hopField, int( /*@ unfolding acc(p.path.Mem(ubScionPath), R50) in (unfolding acc(p.path.Base.Mem(), R55) in @*/ p.path.PathMeta.CurrHF /*@ ) @*/) /*@ , ubScionPath @*/); err != nil { // @ sl.Unslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) // @ sl.CombineAtIndex_Bytes(ub, 0, startScionP, slayers.CmnHdrLen, R54) - // @ sl.CombineRange_Bytes(ub, startScionP, endScionP, writePerm) + // @ sl.CombineRangeWithViews_Bytes(ub, startScionP, endScionP, writePerm, sl.View(ub, 0, startScionP), sl.View(ub[startScionP:endScionP], 0, (endScionP)-(startScionP)), sl.View(ub, endScionP, len(ub))) // @ ghost if typeOf(p.scionLayer.Path) == *epic.Path { fold acc(p.scionLayer.Path.Mem(ubPath), R20) } // @ 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, startScionP, endScionP, HalfPerm) - // @ slayers.IsSupportedPktSubslice(ub, slayers.CmnHdrLen) - // @ slayers.GetPathTypeSubslice(ub, slayers.CmnHdrLen) + // @ sl.CombineRangeWithViews_Bytes(ub, startScionP, endScionP, HalfPerm, sl.View(ub, 0, startScionP), sl.View(ub[startScionP:endScionP], 0, (endScionP)-(startScionP)), sl.View(ub, endScionP, len(ub))) + // @ assert sl.View(ub, 0, startScionP) == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:startScionP] == vHdrPre + // @ assert sl.View(ub, 0, len(ub))[:slayers.CmnHdrLen] == vHdrPre[:slayers.CmnHdrLen] + // @ slayers.IsSupportedPktSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) + // @ slayers.GetPathTypeSubslice(sl.View(ub, 0, len(ub)), slayers.CmnHdrLen) // @ sl.Unslice_Bytes(ub, 0, slayers.CmnHdrLen, R54) // @ sl.CombineAtIndex_Bytes(ub, 0, startScionP, slayers.CmnHdrLen, R54) - // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ub, startScionP) + // @ assert sl.View(ub, 0, len(ub))[:startScionP] == sl.View(ub, 0, startScionP) + // @ p.scionLayer.ValidHeaderOffsetFromSubSliceLemma(ub, sl.View(ub, 0, len(ub)), startScionP) // @ p.SubSliceAbsPktToAbsPkt(ub, startScionP, endScionP) - // @ 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, startScionP, endScionP, HalfPerm) // @ ghost if typeOf(p.scionLayer.Path) == *epic.Path { fold acc(p.scionLayer.Path.Mem(ubPath), R20) } // @ fold acc(p.scionLayer.Mem(ub), R20) @@ -4014,9 +4086,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) @@ -4045,16 +4117,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) { @@ -4119,12 +4191,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 } @@ -4160,15 +4232,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) @@ -4186,7 +4258,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 } @@ -4245,12 +4317,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{}) @@ -4273,12 +4345,12 @@ func (p *scionPacketProcessor) process( } // @ assert p.path === p.scionLayer.GetScionPath(ub) // @ 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 { @@ -4308,8 +4380,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) @@ -4320,7 +4392,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 { @@ -4340,10 +4412,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. @@ -4370,9 +4442,9 @@ func (p *scionPacketProcessor) process( } // @ assert p.path === p.scionLayer.GetScionPath(ub) // @ assert p.scionLayer.UBScionPath(ub) === ubScionPath - // @ 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) @*/ @@ -4408,12 +4480,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() @@ -4426,16 +4498,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 @*/ } @@ -4446,14 +4518,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 @*/ } @@ -4470,7 +4542,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) @*/ @@ -4503,10 +4575,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 @*/) { @@ -4608,7 +4680,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() @@ -4673,7 +4745,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(), _) @@ -4764,12 +4836,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 @@ -4781,25 +4853,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 } @@ -4915,7 +5004,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, @@ -5145,11 +5234,11 @@ func (p *scionPacketProcessor) prepareSCMP( // @ ensures reterr == nil ==> base.Mem(data) // @ ensures reterr == nil && slayers.CmnHdrLen <= len(data) && // @ typeOf(base.GetPath(data)) == *scion.Raw && -// @ path.Type(slayers.GetPathType(data)) != epic.PathType ==> +// @ path.Type(slayers.GetPathType(sl.View(data, 0, len(data)))) != epic.PathType ==> // @ base.EqAbsHeader(data) && base.ValidScionInitSpec(data) // @ ensures reterr == nil && slayers.CmnHdrLen <= len(data) && // @ typeOf(base.GetPath(data)) == *epic.Path && -// @ path.Type(slayers.GetPathType(data)) == epic.PathType ==> +// @ path.Type(slayers.GetPathType(sl.View(data, 0, len(data)))) == epic.PathType ==> // @ base.EqAbsHeader(data) && base.ValidScionInitSpec(data) // @ ensures reterr == nil ==> base.EqPathType(data) // @ ensures forall i int :: {&opts[i]}{processed[i]} 0 <= i && i < len(opts) ==> @@ -5191,11 +5280,11 @@ func decodeLayers(data []byte, base *slayers.SCION, opts ...gopacket.DecodingLay // @ invariant base.Mem(oldData) // @ invariant slayers.CmnHdrLen <= len(oldData) && // @ typeOf(base.GetPath(oldData)) == *scion.Raw && - // @ path.Type(slayers.GetPathType(oldData)) != epic.PathType ==> + // @ path.Type(slayers.GetPathType(sl.View(oldData, 0, len(oldData)))) != epic.PathType ==> // @ base.EqAbsHeader(oldData) && base.ValidScionInitSpec(oldData) // @ invariant slayers.CmnHdrLen <= len(oldData) && // @ typeOf(base.GetPath(oldData)) == *epic.Path && - // @ path.Type(slayers.GetPathType(oldData)) == epic.PathType ==> + // @ path.Type(slayers.GetPathType(sl.View(oldData, 0, len(oldData)))) == epic.PathType ==> // @ base.EqAbsHeader(oldData) && base.ValidScionInitSpec(oldData) // @ invariant base.EqPathType(oldData) // @ invariant 0 < len(opts) ==> 0 <= i0 && i0 <= len(opts) diff --git a/router/io-spec-lemmas.gobra b/router/io-spec-lemmas.gobra index 0cc1d6465..89dc96358 100644 --- a/router/io-spec-lemmas.gobra +++ b/router/io-spec-lemmas.gobra @@ -29,13 +29,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 @@ -45,19 +44,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.GetScionPathOffset(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) @@ -119,12 +115,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 @@ -133,7 +129,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 @@ -143,9 +139,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) @@ -230,18 +226,19 @@ ensures end == p.scionLayer.PathScionEndIdx(ub) ensures p.scionLayer.GetPath(ub) === old(p.scionLayer.GetPath(ub)) ensures typeOf(p.scionLayer.GetPath(ub)) != (*epic.Path) ==> p.path === p.scionLayer.GetPath(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 reveal p.scionLayer.ValidHeaderOffset(ub, sl.View(ub, 0, len(ub))) if typeOf(p.scionLayer.Path) == *epic.Path { startP := p.scionLayer.PathStartIdx(ub) unfold acc(p.scionLayer.Path.Mem(ub[startP:end]), R56) @@ -257,11 +254,9 @@ func (p* scionPacketProcessor) EstablishEqAbsHeader(ub []byte, start int, end in assert start == p.scionLayer.PathStartIdx(ub) assert end == p.scionLayer.PathEndIdx(ub) } - assert p.path.GetBase(ub[start:end]).EqAbsHeader(ub[start:end]) + 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 @@ -271,7 +266,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.GetScionPath(ub) -requires slayers.ValidPktMetaHdr(ub) +requires slayers.ValidPktMetaHdr(sl.View(ub, 0, len(ub))) requires start == p.scionLayer.PathScionStartIdx(ub) requires end == p.scionLayer.PathScionEndIdx(ub) requires p.scionLayer.EqAbsHeader(ub) @@ -279,27 +274,28 @@ 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.PathScionStartIdx(ub) ensures end == p.scionLayer.PathScionEndIdx(ub) ensures p.scionLayer.GetPath(ub) === old(p.scionLayer.GetPath(ub)) ensures typeOf(p.scionLayer.GetPath(ub)) != (*epic.Path) ==> p.path === p.scionLayer.GetPath(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.GetScionPath(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)) + reveal p.scionLayer.ValidHeaderOffset(ub, v) if typeOf(p.scionLayer.Path) == *epic.Path { startP := p.scionLayer.PathStartIdx(ub) unfold acc(p.scionLayer.Path.Mem(ub[startP:end]), R56) @@ -315,16 +311,13 @@ func (p* scionPacketProcessor) AbsPktToSubSliceAbsPkt(ub []byte, start int, end assert start == p.scionLayer.PathStartIdx(ub) assert end == p.scionLayer.PathEndIdx(ub) } - assert p.path.GetBase(ub[start:end]).EqAbsHeader(ub[start:end]) + assert p.path.GetBase(ub[start:end]).EqAbsHeader(v[start:end]) fold acc(p.scionLayer.Mem(ub), R56) - assert start == slayers.GetScionPathOffset(ub) + assert start == slayers.GetScionPathOffset(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) @@ -338,11 +331,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 @@ -352,37 +345,38 @@ 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.GetScionPath(ub) -requires scion.validPktMetaHdr(ub[start:end]) +requires scion.validPktMetaHdr(sl.View(ub[start:end], 0, len(ub[start:end]))) requires start == p.scionLayer.PathScionStartIdx(ub) requires end == p.scionLayer.PathScionEndIdx(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))) requires slayers.CmnHdrLen <= len(ub) requires (typeOf(p.scionLayer.GetPath(ub)) == *epic.Path) == - (path.Type(slayers.GetPathType(ub)) == epic.PathType) + (path.Type(slayers.GetPathType(sl.View(ub, 0, len(ub)))) == epic.PathType) 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.PathScionStartIdx(ub) ensures end == p.scionLayer.PathScionEndIdx(ub) ensures p.scionLayer.GetPath(ub) === old(p.scionLayer.GetPath(ub)) ensures typeOf(p.scionLayer.GetPath(ub)) != (*epic.Path) ==> p.path === p.scionLayer.GetPath(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.GetScionPath(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.path.Mem(ub[start:end]), R56) - reveal p.scionLayer.ValidHeaderOffset(ub, len(ub)) - reveal scion.validPktMetaHdr(ub[start:end]) + reveal p.scionLayer.ValidHeaderOffset(ub, v) + reveal scion.validPktMetaHdr(v[start:end]) if typeOf(p.scionLayer.Path) == *epic.Path { startP := p.scionLayer.PathStartIdx(ub) unfold acc(p.scionLayer.Path.Mem(ub[startP:end]), R56) @@ -401,15 +395,12 @@ func (p* scionPacketProcessor) SubSliceAbsPktToAbsPkt(ub []byte, start int, end assert reveal p.scionLayer.EqAbsHeader(ub) fold acc(p.path.Mem(ub[start:end]), R56) fold acc(p.scionLayer.Mem(ub), R56) - assert start == slayers.GetScionPathOffset(ub) - assert reveal slayers.ValidPktMetaHdr(ub) + assert start == slayers.GetScionPathOffset(v) + assert reveal slayers.ValidPktMetaHdr(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) @@ -423,11 +414,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 3d813fbd8..757ce98df 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.GetScionPathOffset(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 3c41ee431..a2ae55af4 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,55 @@ 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.GetScionPathOffset(raw) headerOffset2 := slayers.GetScionPathOffset(raw[:length]) + assert raw[:length][9] == raw[9] + assert raw[:length][8] == raw[8] 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