13 use import mach.int.UInt64GMP as Limb
20 let wmpz_add (w u v: mpz_ptr) : unit
21 requires { mpz.alloc[w] >= 1 /\ mpz.alloc[u] >= 1 /\ mpz.alloc[v] >= 1 }
22 requires { mpz.readers[w] = 0 /\ mpz.readers[u] = 0 /\ mpz.readers[v] = 0 }
23 requires { mpz.abs_size[u] < max_int32 /\ mpz.abs_size[v] < max_int32 }
24 ensures { value_of w mpz = old (value_of u mpz + value_of v mpz) }
25 ensures { forall x. x <> w -> mpz_unchanged x mpz (old mpz) }
26 ensures { mpz.readers[w] = 0 /\ mpz.readers[u] = 0 /\ mpz.readers[v] = 0 }
27 = [@vc:do_not_keep_trace] (* traceability info breaks the proofs *)
31 let ref usize = size_of u in
32 let ref vsize = size_of v in
33 let ref abs_usize = abs usize in
34 let ref abs_vsize = abs vsize in
36 ensures { mpz.abs_size[u] = abs_usize /\ mpz.abs_size[v] = abs_vsize }
37 ensures { abs_vsize <= abs_usize < max_int32 }
38 ensures { 0 <= abs_vsize <= mpz.alloc[v] }
39 ensures { 0 <= abs_usize <= mpz.alloc[u] }
40 ensures { mpz.alloc[u] > 0 /\ mpz.alloc[v] > 0 }
41 ensures { mpz.readers[u] = 0 /\ mpz.readers[v] = 0 }
42 ensures { abs_usize * mpz.sgn[u] = usize /\
43 abs_vsize * mpz.sgn[v] = vsize }
44 ensures { value_of u mpz + value_of v mpz
45 = old (value_of u mpz + value_of v mpz) }
46 ensures { mpz_unchanged u mpz (old mpz) }
47 ensures { mpz_unchanged v mpz (old mpz) }
48 if Int32.(<) abs_usize abs_vsize
51 let ref tmp_size = vsize in
54 tmp_size <- abs_vsize;
55 abs_vsize <- abs_usize;
56 abs_usize <- tmp_size;
59 let ref wsize = Int32.(+) abs_usize 1 in
60 let uw = mpz_eq u w in
61 let vw = mpz_eq v w in
63 let ompz = pure { mpz } in
64 let wp = wmpz_realloc w wsize in
65 assert { uw \/ mpz_unchanged u mpz ompz };
66 assert { vw \/ mpz_unchanged v mpz ompz };
67 assert { forall x. x <> w -> mpz_unchanged x mpz (mpz at Start) };
69 if (bxor usize vsize < 0)
71 ensures { sgn_value wp wsize
72 = (value_of u mpz + value_of v mpz) at Op }
73 ensures { uw \/ mpz.readers[u] = 0 }
74 ensures { vw \/ mpz.readers[v] = 0 }
75 ensures { mpz.readers[w] = -1 }
76 ensures { forall x. x <> w -> mpz_unchanged x mpz (mpz at Start) }
77 ensures { abs wsize <= plength wp }
78 ensures { wsize <> 0 ->
79 value wp (abs wsize) >= power radix (abs wsize - 1) }
80 ensures { mpz.alloc[u] > 0 /\ mpz.alloc[v] > 0 }
81 ensures { min wp = old min wp /\ max wp = old max wp
82 /\ plength wp = old plength wp }
83 assert { (usize >= 0 /\ vsize < 0)
84 \/ (usize < 0 /\ vsize >= 0) };
85 if abs_usize <> abs_vsize
87 begin ensures { value wp abs_usize
88 = old (mpz.abs_value_of[u] - mpz.abs_value_of[v]) }
89 ensures { uw \/ mpz.readers[u] = 0 }
90 ensures { vw \/ mpz.readers[v] = 0 }
91 ensures { mpz.alloc[u] > 0 /\ mpz.alloc[v] > 0 }
92 ensures { mpz.readers[w] = -1 }
93 ensures { forall x. x <> w -> mpz_unchanged x mpz (mpz at Start) }
94 ensures { min wp = old min wp /\ max wp = old max wp
95 /\ plength wp = old plength wp }
99 let vp = get_read_ptr v in
100 let _b = sub_rx wp abs_usize vp abs_vsize in
105 let up = get_read_ptr u in
106 let _b = sub_ry up abs_usize wp abs_vsize in
110 let up = get_read_ptr u in
111 let vp = get_read_ptr v in
112 let _b = sub wp up abs_usize vp abs_vsize in
120 if usize < 0 then wsize <- -wsize;
121 assert { sgn_value wp wsize = old (value_of u mpz + value_of v mpz)
123 then sgn_value wp wsize = - value wp (-wsize)
124 = - old (mpz.abs_value_of[u] - mpz.abs_value_of[v])
125 = old (value_of u mpz + value_of v mpz)
127 else sgn_value wp wsize = value wp wsize
128 = old (mpz.abs_value_of[u] - mpz.abs_value_of[v])
129 = old (value_of u mpz + value_of v mpz)
137 let vp = get_read_ptr v in
138 if wmpn_cmp wp vp abs_usize < 0
140 let _b = sub_n_ry vp wp abs_usize in
146 let _b = sub_n_rx wp vp abs_usize in
149 if usize < 0 then wsize <- -wsize
154 let up = get_read_ptr u in
155 if wmpn_cmp up wp abs_usize < 0
157 let _b = sub_n_rx wp up abs_usize in
160 if usize >= 0 then wsize <- - wsize
162 let _b = sub_n_ry up wp abs_usize in
165 if usize < 0 then wsize <- - wsize
169 let up = get_read_ptr u in
170 let vp = get_read_ptr v in
171 if wmpn_cmp up vp abs_usize < 0
173 let _b = sub_n wp vp up abs_usize in
176 if usize >= 0 then wsize <- -wsize
178 let _b = sub_n wp up vp abs_usize in
181 if usize < 0 then wsize <- -wsize
189 assert { (usize >= 0 /\ vsize >= 0)
190 \/ (usize < 0 /\ vsize < 0) };
192 begin ensures { value wp wsize = old abs (value_of u mpz + value_of v mpz) }
193 ensures { uw \/ mpz.readers[u] = 0 }
194 ensures { vw \/ mpz.readers[v] = 0 }
195 ensures { mpz.readers[w] = -1 }
196 ensures { forall x. x <> w -> mpz_unchanged x mpz (mpz at Start) }
197 ensures { wsize <> 0 ->
198 value wp (abs wsize) >= power radix (abs wsize - 1) }
199 ensures { min wp = old min wp /\ max wp = old max wp
200 /\ plength wp = old plength wp }
201 ensures { abs_usize <= wsize <= plength wp }
202 assert { abs (value_of u mpz + value_of v mpz)
203 = abs (value_of u mpz) + abs (value_of v mpz)
206 so abs (value_of u mpz) = value_of u mpz
207 so abs (value_of v mpz) = value_of v mpz
209 so abs (value_of u mpz) = - value_of u mpz
210 so abs (value_of v mpz) = - value_of v mpz };
214 cy <- add_n_rxy wp abs_vsize;
215 assert { value wp abs_usize + power radix abs_usize * cy
216 = abs (value_of u mpz + value_of v mpz) };
219 let vp = get_read_ptr v in
220 cy <- add_rx wp abs_usize vp abs_vsize;
221 assert { value wp abs_usize + power radix abs_usize * cy
222 = abs (value_of u mpz + value_of v mpz)
223 by value vp abs_vsize = abs (value_of v mpz)
224 so value wp abs_usize at Op = abs (value_of u mpz)};
229 let up = get_read_ptr u in
230 assert { value wp abs_vsize = abs (value_of v mpz) };
231 assert { value up abs_usize = abs (value_of u mpz) };
232 cy <- add_ry up abs_usize wp abs_vsize;
233 assert { value wp abs_usize + power radix abs_usize * cy
234 = abs (value_of u mpz + value_of v mpz)
235 by value up abs_usize = abs (value_of u mpz) };
239 let up = get_read_ptr u in
240 let vp = get_read_ptr v in
241 assert { value up abs_usize = abs (value_of u mpz)
242 /\ value vp abs_vsize = abs (value_of v mpz) };
243 cy <- add wp up abs_usize vp abs_vsize;
244 assert { value wp abs_usize + power radix abs_usize * cy
245 = abs (value_of u mpz + value_of v mpz)
246 by value up abs_usize = abs (value_of u mpz)
247 so value vp abs_vsize = abs (value_of v mpz) };
252 value_sub_update_no_change (pelts wp) (int32'int abs_usize)
253 0 (int32'int abs_usize) cy;
254 set_ofs wp abs_usize cy;
255 value_tail wp abs_usize;
256 assert { value wp (abs_usize + 1)
257 = value wp abs_usize at Set + power radix abs_usize * cy
258 = abs (value_of u mpz + value_of v mpz) };
259 begin ensures { if cy = 0 then wsize = abs_usize
260 else wsize = abs_usize + 1 }
261 wsize <- abs_usize + Limb.to_int32 cy;
262 value_tail wp abs_usize;
264 assert { wsize <> 0 -> value wp wsize >= power radix (wsize - 1)
267 then wsize = abs_usize
268 so abs_usize = ompz.abs_size u >= 1
269 so value wp wsize >= ompz.abs_value_of u
270 >= power radix (abs_usize - 1)
272 = value wp abs_usize + power radix abs_usize * cy
273 >= power radix abs_usize * cy = power radix abs_usize };
278 wsize <- Int32.(-_) wsize;
279 assert { sgn_value wp wsize = - value wp (wsize at Minus)
280 = - abs (value_of u mpz + value_of v mpz) at Op
281 = (value_of u mpz + value_of v mpz) at Op
282 by usize < 0 so vsize <= 0
283 so value_of u mpz at Op < 0
284 so value_of v mpz at Op <= 0
285 so (value_of u mpz + value_of v mpz) at Op < 0 };
288 assert { sgn_value wp wsize = value wp wsize
289 = (value_of u mpz + value_of v mpz) at Op
290 by usize >= 0 so vsize >= 0
291 so value_of u mpz at Op >= 0
292 so value_of v mpz at Op >= 0
293 so abs (value_of u mpz + value_of v mpz) at Op
294 = (value_of u mpz + value_of v mpz) at Op
295 so wsize >= abs_usize >= 0 }
297 assert { sgn_value wp wsize = (value_of u mpz + value_of v mpz) at Op }
300 assert { value_of w mpz = sgn_value wp wsize
301 = (value_of u mpz + value_of v mpz) at Op };
307 let wmpz_add_ui (w u: mpz_ptr) (v: uint64) : unit
308 requires { mpz.alloc[w] >= 1 /\ mpz.alloc[u] >= 1 }
309 requires { mpz.readers[w] = 0 /\ mpz.readers[u] = 0 }
310 requires { mpz.abs_size[u] < max_int32 }
311 ensures { value_of w mpz = old (value_of u mpz + v) }
312 ensures { forall x. x <> w -> mpz_unchanged x mpz (old mpz) }
313 ensures { mpz.readers[w] = 0 /\ mpz.readers[u] = 0 }
316 let usize = size_of u in
319 let wp = get_write_ptr w in
321 assert { value wp 1 = v };
322 set_size w (if v <> 0 then 1 else 0) wp;
323 assert { value_of w mpz = v };
327 let abs_usize = abs usize in
328 assert { 0 <= abs_usize <= mpz.alloc[u] };
329 let uw = mpz_eq u w in
330 let ref wsize = abs_usize + 1 in
331 let ghost ompz = pure { mpz } in
332 let wp = wmpz_realloc w wsize in
333 assert { uw \/ mpz_unchanged u mpz ompz };
334 assert { forall x. x <> w -> mpz_unchanged x mpz (mpz at Start) };
338 begin ensures { value wp abs_usize + power radix abs_usize * cy
339 = old (value_of u mpz + v) }
340 ensures { 0 <= cy <= 1 }
341 ensures { uw \/ mpz.readers[u] = 0 }
342 ensures { mpz.readers[w] = -1 }
343 ensures { forall x. x <> w -> mpz_unchanged x mpz (mpz at Start) }
346 cy <- wmpn_add_1_in_place wp abs_usize v
348 let up = get_read_ptr u in
349 cy <- wmpn_add_1 wp up abs_usize v;
354 C.set_ofs wp abs_usize cy;
355 value_tail wp abs_usize;
356 assert { value wp (abs_usize + 1)
357 = value wp abs_usize + power radix abs_usize * cy
358 = (value_of u mpz at Start + v)
359 by value wp abs_usize = value wp abs_usize at Carry };
360 wsize <- abs_usize + (Limb.to_int32 cy);
361 assert { value wp wsize = value wp (abs_usize + 1) };
362 assert { value wp wsize = (value_of u mpz at Start + v) };
363 assert { wsize <> 0 -> value wp wsize >= power radix (wsize - 1)
365 then value wp wsize >= value_of u mpz at Start
366 >= power radix (usize - 1)
368 = value wp abs_usize + power radix abs_usize * cy
369 >= power radix abs_usize = power radix (wsize - 1) };
372 begin ensures { sgn_value wp wsize = old (value_of u mpz + v) }
373 ensures { abs wsize <= abs_usize + 1 }
375 -> value wp (abs wsize) >= power radix (abs wsize - 1) }
376 ensures { forall x. x <> w -> mpz_unchanged x mpz (mpz at Start) }
377 ensures { uw \/ mpz.readers[u] = 0 }
378 ensures { mpz.readers[w] = -1 }
380 if (abs_usize = 1 && C.get wp < v)
382 assert { value_of u mpz = - (pelts wp)[0] };
383 C.set wp (v - C.get wp);
385 assert { value wp wsize = value wp 1
386 = v - old (pelts wp)[0]
387 = old (value_of u mpz + v) };
389 assert { v <= value wp abs_usize };
390 assert { value wp abs_usize = - value_of u mpz };
391 assert { value wp abs_usize >= power radix (abs_usize - 1) };
392 let ghost _b = wmpn_sub_1_in_place wp abs_usize v in
394 assert { value wp abs_usize = - value_of u mpz - v };
395 value_tail wp (abs_usize - 1);
396 assert { (pelts wp)[abs_usize - 1] = 0
397 -> value wp (abs_usize - 1) = value wp abs_usize };
398 wsize <- - (abs_usize
399 - (if C.get_ofs wp (abs_usize - 1) = 0 then 1 else 0));
400 assert { sgn_value wp wsize = - value wp (- wsize)
401 = old (value_of u mpz + v) };
403 \/ value wp (abs wsize) >= power radix (abs wsize - 1)
404 by if (pelts wp)[abs_usize - 1] = 0
408 - wsize - 1 = abs_usize - 2
409 so v <= (radix - 1) * 1
410 <= (radix - 1) * (power radix (abs_usize - 2))
411 so power radix (-wsize - 1) + v
412 = power radix (abs_usize - 2) + v
413 <= power radix (abs_usize - 2)
414 + (radix - 1) * power radix (abs_usize - 2)
415 = radix * power radix (abs_usize - 2)
416 = power radix (abs_usize - 1)
418 so value wp abs_usize = 0
421 power radix (-wsize - 1) * 1
422 <= power radix (-wsize - 1) * (pelts wp)[abs_usize - 1]
424 so value wp (abs wsize) = value wp (- wsize)
425 = old (abs_value_of mpz u - v)
426 >= power radix (- wsize - 1)
427 = power radix (abs wsize - 1) }
430 let up = get_read_ptr u in
431 if (abs_usize = 1 && C.get up < v)
433 assert { value_of u mpz = - value up 1 = - (pelts up)[0] };
434 C.set wp (v - C.get up);
436 assert { value wp wsize = v - (pelts up)[0]
437 (*= old (value_of u mpz + v)*) };
439 assert { v <= abs_value_of mpz u };
440 let ghost _b = wmpn_sub_1 wp up abs_usize v in
442 assert { value wp abs_usize = - value_of u mpz - v };
443 value_tail wp (abs_usize - 1);
444 assert { (pelts wp)[abs_usize - 1] = 0
445 -> value wp (abs_usize - 1) = value wp abs_usize };
446 wsize <- - (abs_usize
447 - (if C.get_ofs wp (abs_usize - 1) = 0 then 1 else 0));
448 assert { sgn_value wp wsize = - value wp (- wsize)
449 = old (value_of u mpz + v) };
451 \/ value wp (abs wsize) >= power radix (abs wsize - 1)
452 by if (pelts wp)[abs_usize - 1] = 0
456 - wsize - 1 = abs_usize - 2
457 so v <= (radix - 1) * 1
458 <= (radix - 1) * (power radix (abs_usize - 2))
459 so power radix (-wsize - 1) + v
460 = power radix (abs_usize - 2) + v
461 <= power radix (abs_usize - 2)
462 + (radix - 1) * power radix (abs_usize - 2)
463 = radix * power radix (abs_usize - 2)
464 = power radix (abs_usize - 1)
466 so value wp abs_usize = 0
469 power radix (-wsize - 1) * 1
470 <= power radix (-wsize - 1) * (pelts wp)[abs_usize - 1]
472 so value wp (abs wsize) = value wp (- wsize)
473 = old (abs_value_of mpz u - v)
474 >= power radix (- wsize - 1)
475 = power radix (abs wsize - 1) }