---
# System prepended metadata

title: Library Spec

---

# Library Spec

```javascript=

forall b. exists t. b ~ t

A)

// ok ==> b ~ t
b, ok, t := receive()

x, ok := decrypt(key, message) // ok ==> x in B
if !ok { return }
//POSTCONDITION: exists k, p :: message ~ enc(k, p)

axiom {
  forall b: []byte :: b in B ==> exists t: Term :: b ~ t
}

NiceBytes = { b | exists t. b ~ t }



B1)

x, ok := decrypt(key, message)
if !ok { return }
//POSTCONDITION: forall k, p :: key ~ k && x ~ p ==> message ~ enc(k, p)
//TOTALITY: exists p :: x ~ p 
//ENTAILS: exists k, p :: message ~ enc(k, p)

axiom {
  forall b: []byte :: exists t: Term :: b ~ t      (t might be garbage)
}

// ok ==> forall x, y :: l ~ x && r ~ y ==> b ~ pair(x,y)
l, r, ok := unpair(b)




Criticel Term Axioms: 
  forall b in Bytes. p in CriticalTerms. t in GroundTerms.
    (exists \sigma. b ~ p\sigma) && b ~ t ==> (exists \sigma. t == p \sigma)



method example1()
{
  var b: ByteString; var t: Term
  b, ok, t := receive() // expect <x, h(x)>
  if (!ok) { goto end }

  var l: ByteString; var r: ByteString; var x: Term var y: Term
  l, r, ok, x, y := unpair(b)
  if (!ok) { goto end }

  var v: ByteString
  v := hash(l)

  ok := equals(v, r)
  if (!ok) { goto end }

  assert b ~ t && b ~ pair(x, h(x)) && l ~ x
  
  // by CriticalTerm Axiom:
  assert exists x2 :: t == pair(x2, h(x2)) && l ~ x
  
  { // with forall x', y' :: l ~ x' && r ~ y' <== b ~ pair(x',y') 
      we know b ~ t and t == pair(x2, h(x2)) for some x2
      thus l ~ x2
  }
  
  // goal: l ~ x2
}


ensures forall x, y :: l ~ x && r ~ y ==> b ~ pair(x,y)
func makePair(l, r []byte) (b []byte)

ensures ok ==> forall x, y :: l ~ x && r ~ y <==> b ~ pair(x,y) 
IGLOO: ensures ok ==> alpha(b) == pair(alpha(l), alpha(r))
func unpair(b byte[]) (l, r []byte, ok bool)


b := makePair(l,r)
l2, r2 := unpair(b)
assert l == l2 && r == r2


assume l ~ x && r ~ y 
b := makePair(l,r)
l2, r2 := unpair(b)
assert l2 ~ x && r2 ~ y 




ensures ok <==> len(b) == lsize + rsize
ensures ok  ==> len(l) == lsize && l == b[0:lsize]
ensures ok  ==> len(r) == rsize && r == b[lsize:rsize]
ensures ok  ==> forall x, y :: l ~ x && r ~ y ==> b ~ pair(x, y)

Variant 1)
  ensures ok  ==> forall x, y :: len(gamma(x)) == lsize && len(gamma(y)) == rsize && b ~ pair(x,y) ==> l ~ x && r ~ y
  
Variant 2)
  ensures ok  ==> forall x, y :: (exists u. u ~ x && len(u) == lsize) && (exists u. u ~ y && len(u) == rsize) && b ~ pair(x,y) ==> l ~ x && r ~ y
  
Variant 3)
  ensures ok  ==> forall x, y :: (forall u. u ~ x && len(u) == lsize) && (forall u. u ~ y && len(u) == rsize) && b ~ pair(x,y) ==> l ~ x && r ~ y

func split(b, lsize, rsize) (l, r, ok)



size(enc(k,x)) == 16 + size(x)
size(h(x)) == 18
size('n') == 4
size(<l,r>) == size(l) + size(r)

axiom {
  forall b, x, y :: b is Pair ==> Left(b) ~ x && Right(b) ~ y ==> b ~ pair(x,y)
  forall l, r :: Left(Pair(l,r)) == l && Right(Pair(l,r)) == r
}



ensures ok ==> forall t1, t2, t3, t4, t5 :: 
    x1 ~ t1 && ... && x5 ~ t5 <==> b ~ <'1', t1, t2, t3, t4, t5>
func unmarshal1(b) (x1, x2, x3, x4, x5, ok)

ensures ok ==> forall t1, t2, t3, t4 :: 
    x1 ~ t1 && ... && x4 ~ t4 <==> b ~ <'2', t1, t2, t3, t4>
func unmarshal2(b) (x1, x2, x3, x4, ok)

ensures ok ==> forall t1, t2, t3 :: 
    x1 ~ t1 && ... && x3 ~ t3 <==> b ~ <'4', t1, t2, t3>
func unmarshal3(b) (x1, x2, x3, ok)








ensures ok ==> forall k, p, m :: key ~ k ==> (pla ~ p <==> msg ~ m)
func decrypt(key, msg) (pla, ok)


ensures ok ==> forall x, y :: l ~ x && r ~ y <==> b ~ pair(x,y)







SDEC(key, SENC(key, msg)) == msg




// terms instantiating a pattern p:
//   Q_p = Inst(p) = { p\sigma | dom(\sigma) = vars(p) && \sigma ground }
// term-related bytestrings: 
//   B = {b | exists t. b ~ t} \subset Bytes   (no garbage term!)
// image of b under ~:
//   T(b) = {t | b ~ t}
// 
// Q-axiom:  b ~ t && b ~ u && u in Q_p ==> t in Q_p
//   equiv:  T(b) \subseteq Q_p || T(b) \subseteq Terms-Q_p
//   
// Totality: exists t. b ~ t       (Terms includes a special junk/garbage term)
//    equiv: T(b) != {}            (only needed in scenario B1)
// 
// term construction: b1 ~ t1 && ... && bn ~ tn ==> F(b1, ..., bn) ~ f(t1, ..., tn)
// (used in a form or another in the library specifications)
//
// b, t = recv()
// { b ~ t }  // scenario A 
// (res, b1, ..., bn) = parser(b, p(x1,..., xn))
// { b1, ..., bn in B }
// { exists t'. b ~ t' && t' in Q_p }
// { t in Q_p }      (by Q-axiom)

// Scenarios
// A.  only consider bytestrings in B (no junk term needed)
//     problem to solve: ~ not a function, i.e., potentially several correct interpretations
// B1. all of Bytes + junk constant + ~ total
// B2. all of Bytes, no junk constant, ~ not total, received b may contain junk bytestring bi
//     Problem: if bi is a junk byte string then b not in B!
//
// junk term: term with junk constant as subterm
// junk bytestring: b not in B


//////////////////////////////
////   Type Definitions   ////
//////////////////////////////

domain Term {
  function pair(l: Term, r: Term): Term
  function h(t: Term): Term
  function enc(k: Term, p: Term): Term
  function const(v: Int): Term
}

domain ByteString { 
  function len(b: ByteString): Int
}

domain Alpha {
  function consistent(b: ByteString, t: Term): Bool
}

domain Assumption {
  function Q(t: Term): Bool

  function firstVersionOfQAxiom(): Bool // used to toggle on the axiom

  axiom FirstVersionOfQAxiom {
    // forall t :: t in Q ==> forall b :: b ~ t ==> forall t':: b ~ t' ==> t' == t
    firstVersionOfQAxiom() ==> forall t: Term, b: ByteString, t2: Term :: {Q(t), consistent(b, t), consistent(b, t2)} 
      Q(t) && consistent(b, t) && consistent(b, t2) ==> t == t2
  }

  axiom SecondVersionOfQAxiom {
    // forall p in Q, b. (exists sigma :: b ~ p sigma) ==> forall t. b ~ t ==> exists sigma :: t == p sigma
    true 
    // Not straightforwardly expressible in Viper due to the substitutions.
    // Instead, we instantiate the axiom for each p in Q to simplify the axiom and remove the substitutions.

    // Example for p == <x, h(x)>
    // forall b, x :: b ~ <x, h(x)> ==> forall t :: b ~ t ==> exists x' :: t == <x', h(x')> 
  }
}


//////////////////////////////
////       Utility        ////
//////////////////////////////

method equals(l: ByteString, r: ByteString) returns (ok: Bool)
  ensures ok ==> l == r

method receive() returns (b: ByteString, ok: Bool, /* ghost */ t: Term)
  ensures ok ==> consistent(b, t)



//////////////////////////////
////       Library        ////
//////////////////////////////

// ensures forall t :: b ~ t ==> v ~ h(t)
method hash(b: ByteString) returns (v: ByteString) 
  ensures forall t: Term :: {consistent(b, t)} consistent(b, t) ==> consistent(v, h(t)) 

// ensures ok ==> l ~ x && r ~ y && forall x', y' :: l ~ x' && r ~ y' ==> b ~ <x',y'>
method parse1(b: ByteString) returns (l: ByteString, r: ByteString, ok: Bool, /* ghost */ x: Term, y: Term)
  ensures  ok ==> len(l) == 32 && len(r) == 32
  ensures  ok ==> (
    consistent(l, x) && consistent(r, y) &&
    forall x2: Term, y2: Term :: {consistent(l, x2), consistent(r, y2)} consistent(l, x2) && consistent(r, y2) ==> consistent(b, pair(x2,y2)) 
  )

// ensures ok ==> b ~ constant(v)
method parseConst(b: ByteString) returns (v: Int, ok: Bool)
  ensures ok ==> consistent(b, const(v)) 

// ensures b ~ constant(v)
method makeConst(v: Int) returns (b: ByteString)
  ensures consistent(b, const(v))

// ensures ok ==> forall k, p :: key ~ k && pla ~ p ==> cip ~ enc(k,p)
method encrypt(key: ByteString, pla: ByteString) returns (cip: ByteString, ok: Bool)
  ensures ok ==> forall k: Term, p: Term :: {consistent(key,k),consistent(pla,p)} 
    consistent(key,k) && consistent(pla,p) ==> consistent(cip,enc(k,p)) 

// ensures ok ==> forall k, m :: key ~ k && cip ~ m ==> (exists p :: pla ~ p) && (forall p :: pla ~ p ==> cip ~ enc(k,p))
method decryptVersion2(key: ByteString, cip: ByteString) returns (pla: ByteString, ok: Bool)
  ensures ok ==> forall k: Term, m: Term :: {consistent(key, k), consistent(cip, m)}
    consistent(key, k) && consistent(cip, m) ==> (
      (exists p: Term :: consistent(pla, p)) &&
      (forall p: Term :: {consistent(pla, p)} consistent(pla, p) ==> consistent(cip, enc(k, p)))
    )

// ensures ok ==> forall k, p :: key ~ k && pla ~ p ==> cip ~ enc(k,p)
method decryptVersion1(key: ByteString, cip: ByteString) returns (pla: ByteString, ok: Bool)
  ensures ok ==> forall k: Term, p: Term :: {consistent(key,k),consistent(pla,p)} 
    consistent(key,k) && consistent(pla,p) ==> consistent(cip,enc(k,p))



//////////////////////////////
////       Examples       ////
//////////////////////////////

// terms instantiating a pattern p:
//   Q_p = Inst(p) = { p\sigma | dom(\sigma) = vars(p) && \sigma ground }
// term-related bytestrings: 
//   B = {b | exists t. b ~ t} \subset Bytes   (no garbage term!)
// image of b under ~:
//   T(b) = {t | b ~ t}
// 
// Q-axiom:  b ~ t && b ~ u && u in Q_p ==> t in Q_p
//   equiv:  T(b) \subseteq Q_p || T(b) \subseteq Terms-Q_p

/*
// forall b in Bytes. forall p in CriticalTerm. forall t in GroundTerm.
//     (exists \sigma. b ~ p\sigma) && b ~ t ==> exists \sigma. t == p\sigma
  
b := receive() // expecting <x,h(x)>
// exists t. b ~ t && in(t)

ok, b' := perform_parsing(b)
// ok ==> exists x. b ~ <x, h(x)> && b' ~ x


// goal: in(t') \in soup with exists x. t' == <x,h(x)>
// continue with the protocol

*/


// Example 1 - <x, h(x)>

method code1() returns (res: Term, ok: Bool)
  /* With the first version of the axiom */
  // requires firstVersionOfQAxiom()
  // // forall t, b :: b ~ t && len(b) == 32 ==> <t, h(t)> in Q
  // requires forall t: Term, b: ByteString :: {consistent(b, t)} consistent(b, t) && len(b) == 32 ==> Q(pair(t, h(t)))
  /* With the second version of the axiom */
  // forall b, x :: b ~ <x, h(x)> ==> forall t :: b ~ t ==> exists x' :: t == <x',h(x')>
  requires forall b: ByteString, x: Term :: {consistent(b, pair(x, h(x)))} 
    consistent(b, pair(x, h(x))) ==> 
      forall t: Term :: {consistent(b, t)} consistent(b, t) ==> exists x2: Term :: t == pair(x2, h(x2))

  ensures ok ==> exists x: Term :: res == pair(x, h(x))
{
  var b: ByteString; var t: Term
  b, ok, t := receive() // expect <x, h(x)>
  if (!ok) { goto end }

  var l: ByteString; var r: ByteString; var x: Term var y: Term
  l, r, ok, x, y := parse1(b)
  if (!ok) { goto end }

  var v: ByteString
  v := hash(l)

  ok := equals(v, r)
  if (!ok) { goto end }

  assert exists x2: Term :: t == pair(x2, h(x2))
  res := t

  label end
}



// Example 2 - <'4', h('17')>

method code2() // uses parseConst
  /* With the first version of the axiom */
  requires firstVersionOfQAxiom()
  // <'4', h('17')> in Q
  requires Q(pair(const(4), h(const(17))))
  /* The second version of the axiom is essentially the same for constant terms */
{
  var b: ByteString; var t: Term; var ok: Bool
  b, ok, t := receive() // expect <'4', h('17')>
  if (!ok) { goto end }

  var l: ByteString; var r: ByteString; var x: Term var y: Term
  l, r, ok, x, y := parse1(b)
  if (!ok) { goto end }

  var v1: Int
  v1, ok := parseConst(l)
  if (!ok || v1 != 4) { goto end } 

  var v2: ByteString;
  v2 := makeConst(17)
  v2 := hash(v2)
  ok := equals(r, v2)
  if (!ok) { goto end }

  assert t == pair(const(4), h(const(17)))

  label end
}


method code3() // uses makeConst
  /* With the first version of the axiom */
  requires firstVersionOfQAxiom()
  // <'4', h('17')> in Q
  requires Q(pair(const(4), h(const(17))))
  /* The second version of the axiom is essentially the same for constant terms */
{
  var b: ByteString; var t: Term; var ok: Bool
  b, ok, t := receive() // expect <'4', h('17')>
  if (!ok) { goto end }

  var l: ByteString; var r: ByteString; var x: Term var y: Term
  l, r, ok, x, y := parse1(b)
  if (!ok) { goto end }

  var v1: ByteString
  v1 := makeConst(4)
  ok := equals(l, v1)
  if (!ok) { goto end }

  var v2: ByteString;
  v2 := makeConst(17)
  v2 := hash(v2)
  ok := equals(r, v2)
  if (!ok) { goto end }

  assert t == pair(const(4), h(const(17)))

  label end
}

method code4() 
  /* With the first version of the axiom */
  // requires firstVersionOfQAxiom()
  // // forall t, b :: b ~ t && len(b) == 32 ==> <t, h('17')> in Q
  // requires forall t: Term, b: ByteString :: {consistent(b, t)} consistent(b, t) && len(b) == 32 ==> Q(pair(t, h(const(17))))
  /* With the second version of the axiom */
  // forall b, x :: b ~ <x, h(x)> ==> forall t :: b ~ t ==> exists x' :: t == <x',h('17')>
  requires forall b: ByteString, x: Term :: {consistent(b, pair(x, h(const(17))))} 
    consistent(b, pair(x, h(const(17)))) ==> 
      forall t: Term :: {consistent(b, t)} consistent(b, t) ==> exists x2: Term :: t == pair(x2, h(const(17)))
{
  var b: ByteString; var t: Term; var ok: Bool
  b, ok, t := receive() // expect <x, h('17')>
  if (!ok) { goto end }

  var l: ByteString; var r: ByteString; var x: Term var y: Term
  l, r, ok, x, y := parse1(b)
  if (!ok) { goto end }

  var v2: ByteString;
  v2 := makeConst(17)
  v2 := hash(v2)
  ok := equals(r, v2)
  if (!ok) { goto end }

  assert exists x2: Term :: t == pair(x2, h(const(17)))

  label end
}


// Example 3 - <x, enc(k,x)>

method code5(bk: ByteString, k: Term) // uses encrypt
  // bk ~ k
  requires consistent(bk, k) 
  /* With the first version of the axiom */
  // requires firstVersionOfQAxiom()
  // // forall t, b :: b ~ t && len(b) == 32 ==> <t,enc(k, t)> in Q
  // requires forall t: Term, b: ByteString :: {consistent(b, t)} consistent(b, t) && len(b) == 32 ==> Q(pair(t, enc(k,t)))
  /* With the second version of the axiom */
  // forall b, x :: b ~ <x, enc(k,x)> ==> forall t :: b ~ t ==> exists x' :: t == <x',enc(k,x')>
  requires forall b: ByteString, x: Term :: {consistent(b, pair(x, enc(k, x)))} 
    consistent(b, pair(x, enc(k, x))) ==> 
      forall t: Term :: {consistent(b, t)} consistent(b, t) ==> exists x2: Term :: t == pair(x2, enc(k, x2))
{
  var b: ByteString; var ok: Bool; var t: Term
  b, ok, t := receive() // expect <x, enc(k,x)>
  if (!ok) { goto end }

  var l: ByteString; var r: ByteString; var x: Term var y: Term
  l, r, ok, x, y := parse1(b)
  if (!ok) { goto end }

  var v: ByteString
  v, ok := encrypt(bk, l)
  if (!ok) { goto end }

  ok := equals(v, r)
  if (!ok) { goto end }

  assert exists x2: Term :: t == pair(x2, enc(k, x2))

  label end
}

method code6(bk: ByteString, k: Term) // uses decrypt
  // bk ~ k
  requires consistent(bk, k) 
  /* With the first version of the axiom */
  // requires firstVersionOfQAxiom()
  // // forall t, b :: b ~ t && len(b) == 32 ==> <t,enc(k, t)> in Q
  // requires forall t: Term, b: ByteString :: {consistent(b, t)} consistent(b, t) && len(b) == 32 ==> Q(pair(t, enc(k,t)))
  /* With the second version of the axiom */
  // forall b, x :: b ~ <x, enc(k,x)> ==> forall t :: b ~ t ==> exists x' :: t == <x',enc(k,x')>
  requires forall b: ByteString, x: Term :: {consistent(b, pair(x, enc(k, x)))} 
    consistent(b, pair(x, enc(k, x))) ==> 
      forall t: Term :: {consistent(b, t)} consistent(b, t) ==> exists x2: Term :: t == pair(x2, enc(k, x2))
{
  var b: ByteString; var ok: Bool; var t: Term
  b, ok, t := receive() // expect <x, enc(k,x)>
  if (!ok) { goto end }

  var l: ByteString; var r: ByteString; var x: Term var y: Term
  l, r, ok, x, y := parse1(b)
  if (!ok) { goto end }

  var v: ByteString
  v, ok := decryptVersion2(bk, r) // both version work
  if (!ok) { goto end }

  ok := equals(v, l)
  if (!ok) { goto end }

  assert exists x2: Term :: t == pair(x2, enc(k, x2))

  label end
}















method example1()
{
  var b: ByteString; var t: Term
  b, ok, t := receive() // expect <x, h(x)>
  if (!ok) { goto end }

  var l: ByteString; var r: ByteString; var x: Term var y: Term
  l, r, ok, x, y := parse1(b)
  if (!ok) { goto end }

  var v: ByteString
  v := hash(l)

  ok := equals(v, r)
  if (!ok) { goto end }

  assert exists x. b ~ pair(x, h(x)) && l ~ x
 
  
  Q-Axiom:
  (exists x. b ~ <x, h(x)>) && b ~ t ==> exists x°. t == <x°, h(x°)> 
      && get1(b) ~ x° && get2(b) ~ h(x°)
  
  
  (exists \sigma. b ~ p\sigma) && b ~ t ==> 
         exist \sigma. t == \sigma 
      && forall position in Positions(p). position(b) ~ position(\sigma)
  
  <x,h(x)> --> left( . ) in Positions(<x,h(x)>)
  [left( . )] -> get1( . ) 
  
  // goal :: exists x2: Term :: t == pair(x2, h(x2)) && l ~ x2
  
  
  b ~ t /\ b ~ p\sigma /\ b_i ~ \sigma(x_i) for i=1,..,n
  ==> \exists \sigma'. t = p\sigma' /\ b_i ~ \sigma'(x_i) for i=1,..,n
}
```