nat-generic.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. // SPDX-License-Identifier: GPL-2.0 or GPL-3.0
  2. // Copyright © 2019 Ariadne Devos
  3. // Integer model: wrap-around
  4. // Proof status: auto
  5. #include <stdint.h>
  6. #include <sHT/index.h>
  7. #include <sHT/lex/digit.h>
  8. #include <sHT/lex/nat.h>
  9. #include <sHT/logic/arithmetic.h>
  10. #include <sHT/test.h>
  11. #ifdef __FRAMAC__
  12. # include <sHT/math/vector-memory.h>
  13. # include <sHT/math/expnat/lt.h>
  14. #endif
  15. /*@ requires S ==> \valid_read(&c[0 .. e - 1]);
  16. requires S ==> \valid_read(&c[0]);
  17. requires \valid_read(&c[b .. e - 1]);
  18. requires NS ==> b <= i < e;
  19. requires i < e || i == 0;
  20. requires NS ==> X_num_p(vector_load_u8(c + b, e - b));
  21. terminates \true;
  22. assigns \result;
  23. ensures NS ==> \result == X_val(c[i]); */
  24. static inline uint32_t
  25. sHT_X_given_X_num_p(uint8_t *c, size_t b, size_t e, size_t i)
  26. {
  27. /*@ assert NS ==> X_p(\nth(vector_load_u8(c + b, e - b), i - b)); */
  28. /*@ assert NS ==> X_p((c + b)[i - b]); */
  29. return sHT_X_val(c[i]);
  30. }
  31. /** Reduce scope of X_num_p
  32. (Doing i + 1 here avoids overflow later.) */
  33. /*@ requires NS ==> i < n;
  34. requires NS ==> X_num_p(vector_load_u8(c, n));
  35. terminates \true;
  36. assigns \nothing;
  37. ensures NS ==> X_num_p(vector_load_u8(c, i + 1)); */
  38. static inline void
  39. sHT_X_num_p_less(uint8_t *c, size_t n, size_t i)
  40. {
  41. /* Limit range to 0 .. i: elements */
  42. /*@ assert \length(vector_load_u8(c, n)) == n; */
  43. /*@ assert \length(vector_load_u8(c, i + 1)) == i + 1; */
  44. /*@ assert NS ==> ∀ ℤ j; 0 <= j < n
  45. ==> \nth(vector_load_u8(c, n), j) == c[j]; */
  46. /*@ assert NS ==> ∀ ℤ j; 0 <= j < i + 1
  47. ==> \nth(vector_load_u8(c, n), j) == c[j]; */
  48. /*@ assert NS ==> ∀ ℤ j; 0 <= j < i + 1
  49. ==> \nth(vector_load_u8(c, i + 1), j) == c[j]; */
  50. /*@ assert NS ==> ∀ ℤ j; 0 <= j < i + 1
  51. ==> \nth(vector_load_u8(c, n), j) == \nth(vector_load_u8(c, i + 1), j); */
  52. /* Limit range to 0 .. i: predicate*/
  53. /*@ assert NS ==> ∀ ℤ j; 0 <= j < \length(vector_load_u8(c, n))
  54. ==> X_p(\nth(vector_load_u8(c, n), j)); */
  55. /*@ assert NS ==> ∀ ℤ j; 0 <= j < n
  56. ==> X_p(\nth(vector_load_u8(c, n), j)); */
  57. /*@ assert NS ==> ∀ ℤ j; 0 <= j < i + 1
  58. ==> X_p(\nth(vector_load_u8(c, n), j)); */
  59. /*@ assert NS ==> ∀ ℤ j; 0 <= j < i + 1
  60. ==> X_p(\nth(vector_load_u8(c, i + 1), j)); */
  61. }
  62. /*@ requires NS ==> X_num_p(vector_load_u8(c, n));
  63. requires NS ==> k <= n;
  64. terminates \true;
  65. assigns \nothing;
  66. ensures NS ==> X_num_val(vector_load_u8(c, k))
  67. ≤ X_num_val(vector_load_u8(c, n)); */
  68. static inline void
  69. sHT_X_num_val_less_lt(uint8_t *c, size_t n, size_t k)
  70. {
  71. /*@ assert NS ==> ∀ integer j; 0 <= j < \length(vector_load_u8(c, n))
  72. ==> X_p(\nth(vector_load_u8(c, n), j)); */
  73. /*@ assert NS ==> ∀ integer j; 0 <= j < n
  74. ==> X_p(\nth(vector_load_u8(c, n), j)); */
  75. /*@ assert NS ==> ∀ integer j; 0 <= j < n
  76. ==> \nth(vector_load_u8(c, n), j) == c[j]; */
  77. /*@ assert NS ==> ∀ integer j; 0 <= j < n
  78. ==> X_p(c[j]); */
  79. /*@ assert NS ==> ∀ integer j; 0 <= j < n
  80. ==> 0 <= X_val(c[j]) < X_base; */
  81. /*@ loop invariant NS ==> k <= i <= n;
  82. loop invariant NS ==> X_num_val(vector_load_u8(c, k))
  83. ≤ X_num_val(vector_load_u8(c, i));
  84. loop assigns i;
  85. loop variant n - i; */
  86. for (size_t i = k; i < n; i++) {
  87. /* Step X_num_val */
  88. sHT_X_num_p_less(c, n, i);
  89. /*@ assert vector_load_u8(c, i + 1) == (vector_load_u8(c, i) ^ [| c[i] |]); */
  90. /*@ assert NS ==> X_num_p(vector_load_u8(c, i) ^ [| c[i] |]); */
  91. /*@ assert NS ==> X_num_val(vector_load_u8(c, i) ^ [| c[i] |])
  92. == X_base * X_num_val(vector_load_u8(c, i))
  93. + X_val(c[i]); */
  94. /*@ assert NS ==> X_num_val(vector_load_u8(c, i + 1))
  95. == X_base * X_num_val(vector_load_u8(c, i))
  96. + X_val(c[i]); */
  97. /* Bounds on the extra digit */
  98. /*@ assert NS ==> X_p(\nth(vector_load_u8(c, n), i)); */
  99. /*@ assert NS ==> X_p(c[i]); */
  100. /*@ assert NS ==> 0 <= X_val(c[i]) < X_base; */
  101. }
  102. }
  103. uint32_t
  104. sHT_X_to_u32(uint8_t *c, size_t b, size_t e)
  105. {
  106. size_t i = b;
  107. uint32_t x = 0;
  108. if (sHT_ge(b, e))
  109. return x;
  110. /*@ loop invariant NS ==> b <= i < e;
  111. loop invariant NS ==> x == X_num_val(vector_load_u8(c + b, i - b));
  112. loop assigns i, x;
  113. loop variant e - i; */
  114. do { loop: i = sHT_index_nospec(i, e);
  115. sHT_X_num_p_less(c + b, e - b, i - b);
  116. uint32_t y = sHT_X_given_X_num_p(c, b, e, i);
  117. /* Value */
  118. /*@ assert NS ==> vector_load_u8(c + b, i - b + 1)
  119. == (vector_load_u8(c + b, i - b) ^ [| c[i] |]); */
  120. /*@ assert NS ==> X_num_val(vector_load_u8(c + b, i - b + 1))
  121. == X_base * X_num_val(vector_load_u8(c + b, i - b))
  122. + X_val(c[i]); */
  123. /*@ assert NS ==> X_num_val(vector_load_u8(c + b, i - b + 1))
  124. == X_base * X_num_val(vector_load_u8(c + b, i - b))
  125. + y; */
  126. /* Bounds */
  127. sHT_X_num_val_less_lt(c + b, e - b, (i - b) + 1);
  128. /*@ assert NS ==> X_num_val(vector_load_u8(c + b, (i - b) + 1)) <= UINT32_MAX; */
  129. x = sHT_muladd_nooverflowNS_u32(sHT_X_base, x, y);
  130. i++;
  131. } while (sHT_lt(i, e));
  132. return x;
  133. }