Fixpoint json_eqb (j j' : json.t) : bool :=
    let fix loop_arr (l l': list json.t) : bool :=
        match (l, l') with
        | ([], []) => true
        | (j :: l, j' :: l') => andb (json_eqb j j') (loop_arr l l')
        | (_, _) => false
        end in
    let fix loop_obj (l l' : list (String.string * json.t)) : bool :=
        match (l, l') with
        | ([], []) => true
        | ((s, j) :: l, (s', j') :: l') => andb (string_eqb s s')
                                                (andb (json_eqb j j')
                                                      (loop_obj l l'))
        | (_, _) => false
        end in
    match (j, j') with
    | (json.Null, json.Null) => true
    | (json.Bool b, json.Bool b') => Bool.eqb b b'
    | (json.Num n, json.Num n') => Nat.eqb n n'
    | (json.String s, json.String s') => string_eqb s s'
    | (json.Arr l, json.Arr l') => loop_arr l l'
    | (json.Obj l, json.Obj l') => loop_obj l l'
    | _ => false
    end.Definition loop_arr :=
    fix loop_arr (l l': list json.t) : bool :=
      match (l, l') with
      | ([], []) => true
      | (j :: l, j' :: l') => andb (json_eqb j j') (loop_arr l l')
      | (_, _) => false
      end.Definition loop_obj :=
    fix loop_obj (l l' : list (String.string * json.t)) : bool :=
      match (l, l') with
      | ([], []) => true
      | ((s, j) :: l, (s', j') :: l') => andb (string_eqb s s')
                                              (andb (json_eqb j j') (loop_obj l l'))
      | (_, _) => false
      end.

Lemma json_eqb_eq : forall j j', json_eqb j j' = true -> j = j'.