SecureSpecCombinator

Trait SecureSpecCombinator 

Source
pub trait SecureSpecCombinator: SpecCombinator {
    // Required methods
    proof fn theorem_serialize_parse_roundtrip(&self, v: Self::Type);
    proof fn theorem_parse_serialize_roundtrip(&self, buf: Seq<u8>);
    spec fn is_prefix_secure() -> bool;
    proof fn lemma_prefix_secure(&self, s1: Seq<u8>, s2: Seq<u8>);
    proof fn lemma_parse_length(&self, s: Seq<u8>);
    spec fn is_productive(&self) -> bool;
    proof fn lemma_parse_productive(&self, s: Seq<u8>);

    // Provided methods
    proof fn corollary_parse_surjective(&self, v: Self::Type) { ... }
    fn corollary_serialize_injective(&self, v1: Self::Type, v2: Self::Type) { ... }
    fn corollary_serialize_injective_contraposition(
        &self,
        v1: Self::Type,
        v2: Self::Type,
    ) { ... }
    fn corollary_parse_non_malleable(&self, buf1: Seq<u8>, buf2: Seq<u8>) { ... }
    fn lemma_serialize_productive(&self, v: Self::Type) { ... }
}
Expand description

Theorems and lemmas that must be proven for a combinator to be considered correct and secure.

Required Methods§

Source

proof fn theorem_serialize_parse_roundtrip(&self, v: Self::Type)

requires
self.requires(),
ensures
self.wf(v)
    ==> self.spec_parse(self.spec_serialize(v))
        == Some((self.spec_serialize(v).len() as int, v)),

One of the top-level roundtrip properties It reads “if we serialize a (well-formed) value, then parsing the serialized bytes should give us the same value back.” If we somehow get a different value, it means that different high-level values can correspond to the same low-level representation, or put differently, the same byte sequences can be parsed into different values.

This property can be understood as

  1. injectivity of serialization: different values should serialize to different byte sequences
  2. surjectivity of parsing: every valid high-level value should associate with at least one low-level representation.
  3. correctness of parsing: given a correct serializer that produces some byte sequence from a value, the corresponding parser should be able to parse the byte sequence back to the same value (can lead to format-confusion attacks if not satisfied).
Source

proof fn theorem_parse_serialize_roundtrip(&self, buf: Seq<u8>)

requires
self.requires(),
ensures
self
    .spec_parse(
        buf,
    ) matches Some(
    (n, v),
) ==> {
    &&& self.wf(v)
    &&& self.spec_serialize(v) == buf.take(n)

},

One of the top-level roundtrip properties It reads “if we successfully parse a byte sequence, then serializing the parsed value should give us the same byte sequence back.” If we somehow get a different byte sequence, it means that different low-level representations can correspond to the same high-level value, or put differently, the same value can be serialized into different byte sequences.

This property can be understood as

  1. injectivity of parsing: different byte sequences should parse to different values (can lead to parser mallability attacks if not satisfied)
  2. correctness of serialization: given a correct parser that produces some value from a byte sequence, the corresponding serializer should be able to serialize the value back to the same byte sequence (up to the number of bytes consumed).
Source

spec fn is_prefix_secure() -> bool

Like an associated constant, denotes whether the combinator is prefix-secure.

Source

proof fn lemma_prefix_secure(&self, s1: Seq<u8>, s2: Seq<u8>)

requires
self.requires(),
ensures
Self::is_prefix_secure()
    ==> (self.spec_parse(s1) is Some ==> self.spec_parse(s1 + s2) == self.spec_parse(s1)),

This prefix-secure lemma is used in the proof of the roundtrip properties for sequencing and repeating combinators.

Source

proof fn lemma_parse_length(&self, s: Seq<u8>)

requires
self.requires(),
ensures
self.spec_parse(s) matches Some((n, _)) ==> 0 <= n <= s.len(),

The parser-length lemma is used in the proof of the roundtrip properties and the prefix-secure lemma

Source

spec fn is_productive(&self) -> bool

Like an associated constant, denotes whether the combinator is productive

Source

proof fn lemma_parse_productive(&self, s: Seq<u8>)

requires
self.requires(),
ensures
self.is_productive() ==> (self.spec_parse(s) matches Some((n, _)) ==> n > 0),

This lemma is used in the proof of the roundtrip properties for optional and unbounded repeating combinators.

Provided Methods§

Source

proof fn corollary_parse_surjective(&self, v: Self::Type)

requires
self.requires(),
self.wf(v),
ensures
exists |b: Seq<u8>| #[trigger] self.spec_parse(b) matches Some((_, v_)) && v_ == v,

Followed from theorem_serialize_parse_roundtrip

Source

proof fn corollary_serialize_injective(&self, v1: Self::Type, v2: Self::Type)

requires
self.requires(),
ensures
self.wf(v1) && self.wf(v2)
    ==> (self.spec_serialize(v1) == self.spec_serialize(v2) ==> v1 == v2),

Followed from theorem_serialize_parse_roundtrip

Source

proof fn corollary_serialize_injective_contraposition( &self, v1: Self::Type, v2: Self::Type, )

requires
self.requires(),
ensures
self.wf(v1) && self.wf(v2)
    ==> (v1 != v2 ==> self.spec_serialize(v1) != self.spec_serialize(v2)),

Followed from theorem_serialize_parse_roundtrip

Source

proof fn corollary_parse_non_malleable(&self, buf1: Seq<u8>, buf2: Seq<u8>)

requires
self.requires(),
ensures
self
    .spec_parse(
        buf1,
    ) matches Some(
    (n1, v1),
) ==> self
    .spec_parse(
        buf2,
    ) matches Some((n2, v2)) ==> v1 == v2 ==> buf1.take(n1) == buf2.take(n2),

Followed from theorem_parse_serialize_roundtrip

Source

proof fn lemma_serialize_productive(&self, v: Self::Type)

requires
self.requires(),
self.wf(v),
ensures
self.is_productive() ==> self.spec_serialize(v).len() > 0,

This lemma is used in the proof of the roundtrip properties for optional and unbounded repeating combinators.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementations on Foreign Types§

Source§

impl<C: SecureSpecCombinator> SecureSpecCombinator for &C

Source§

open spec fn is_prefix_secure() -> bool

{ C::is_prefix_secure() }
Source§

open spec fn is_productive(&self) -> bool

{ (*self).is_productive() }
Source§

proof fn theorem_serialize_parse_roundtrip(&self, v: Self::Type)

Source§

proof fn theorem_parse_serialize_roundtrip(&self, buf: Seq<u8>)

Source§

proof fn lemma_prefix_secure(&self, s1: Seq<u8>, s2: Seq<u8>)

Source§

proof fn lemma_parse_length(&self, s: Seq<u8>)

Source§

proof fn lemma_parse_productive(&self, s: Seq<u8>)

Source§

impl<C: SecureSpecCombinator> SecureSpecCombinator for Box<C>

Source§

open spec fn is_prefix_secure() -> bool

{ C::is_prefix_secure() }
Source§

open spec fn is_productive(&self) -> bool

{ (**self).is_productive() }
Source§

proof fn theorem_serialize_parse_roundtrip(&self, v: Self::Type)

Source§

proof fn theorem_parse_serialize_roundtrip(&self, buf: Seq<u8>)

Source§

proof fn lemma_prefix_secure(&self, s1: Seq<u8>, s2: Seq<u8>)

Source§

proof fn lemma_parse_length(&self, s: Seq<u8>)

Source§

proof fn lemma_parse_productive(&self, s: Seq<u8>)

Source§

impl<Fst: SecureSpecCombinator, Snd: SecureSpecCombinator> SecureSpecCombinator for (Fst, Snd)

Source§

proof fn theorem_serialize_parse_roundtrip(&self, v: Self::Type)

Source§

proof fn theorem_parse_serialize_roundtrip(&self, buf: Seq<u8>)

Source§

open spec fn is_prefix_secure() -> bool

{ Fst::is_prefix_secure() && Snd::is_prefix_secure() }
Source§

proof fn lemma_prefix_secure(&self, buf: Seq<u8>, s2: Seq<u8>)

Source§

proof fn lemma_parse_length(&self, s: Seq<u8>)

Source§

open spec fn is_productive(&self) -> bool

{ Pair::spec_new(self.0, |r: Fst::Type| self.1).is_productive() }
Source§

proof fn lemma_parse_productive(&self, s: Seq<u8>)

Implementors§

Source§

impl SecureSpecCombinator for BtcVarint

Source§

impl SecureSpecCombinator for Tail

Source§

impl SecureSpecCombinator for Variable

Source§

impl SecureSpecCombinator for End

Source§

impl SecureSpecCombinator for Fail

Source§

impl SecureSpecCombinator for UnsignedLEB128

Source§

impl SecureSpecCombinator for Success

Source§

impl SecureSpecCombinator for U8

Source§

impl SecureSpecCombinator for U16Be

Source§

impl SecureSpecCombinator for U16Le

Source§

impl SecureSpecCombinator for U24Be

Source§

impl SecureSpecCombinator for U24Le

Source§

impl SecureSpecCombinator for U32Be

Source§

impl SecureSpecCombinator for U32Le

Source§

impl SecureSpecCombinator for U64Be

Source§

impl SecureSpecCombinator for U64Le

Source§

impl<C: SecureSpecCombinator> SecureSpecCombinator for Repeat<C>

Source§

impl<C: SecureSpecCombinator> SecureSpecCombinator for RepeatN<C>

Source§

impl<Fst, Snd> SecureSpecCombinator for Choice<Fst, Snd>

Source§

impl<Fst, Snd> SecureSpecCombinator for OptThen<Fst, Snd>

Source§

impl<Fst, Snd> SecureSpecCombinator for SpecPair<Fst, Snd>

Source§

impl<Fst: SecureSpecCombinator<Type = ()>, Snd: SecureSpecCombinator> SecureSpecCombinator for Preceded<Fst, Snd>

Source§

impl<Fst: SecureSpecCombinator, Snd: SecureSpecCombinator<Type = ()>> SecureSpecCombinator for Terminated<Fst, Snd>

Source§

impl<Inner, M> SecureSpecCombinator for Mapped<Inner, M>
where Inner: SecureSpecCombinator, M: SpecIsoProof<Src = Inner::Type>, Inner::Type: SpecFrom<M::Dst>, M::Dst: SpecFrom<Inner::Type>,

Source§

impl<Inner, M> SecureSpecCombinator for TryMap<Inner, M>
where Inner: SecureSpecCombinator, M: SpecPartialIsoProof<Src = Inner::Type>, Inner::Type: SpecTryFrom<M::Dst>, M::Dst: SpecTryFrom<Inner::Type>,

Source§

impl<Inner, P> SecureSpecCombinator for Refined<Inner, P>
where Inner: SecureSpecCombinator, P: SpecPred<Inner::Type>,

Source§

impl<Inner: SecureSpecCombinator> SecureSpecCombinator for Cond<Inner>

Source§

impl<Inner: SecureSpecCombinator<Type = T>, T> SecureSpecCombinator for Tag<Inner, T>

Source§

impl<Next: SecureSpecCombinator> SecureSpecCombinator for AndThen<Variable, Next>

Source§

impl<T: SecureSpecCombinator> SecureSpecCombinator for Opt<T>

Source§

impl<const N: usize> SecureSpecCombinator for Fixed<N>