-
Notifications
You must be signed in to change notification settings - Fork 10
Prove sub
#44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prove sub
#44
Changes from all commits
fe7a70c
7f2eac5
ede60fb
d75c942
d9bf793
cea8650
1292443
226f417
824c76c
9dccb0e
731d328
0d057e9
a409fc5
e61cdd3
734329e
ffe9fac
589c87d
e0fe40f
c203a81
fbb93fd
fc1c61c
dd2697c
8fa7799
dd6d82f
557e9cf
6586119
6c0aed2
5a73321
a7c5cda
f033d53
141388d
15c9087
2d6126a
7e7a24c
4b6f0c2
2ffb7b5
e52f2e6
e12f9c8
b419698
9219b23
8cfd57a
d85fd1e
f125c7f
cf0ebea
9ea42a5
5f53876
37f6fe0
b6d8986
d81a76e
8cb27dd
8016706
f537584
50087ae
69d037f
836be91
264b4cd
90d864b
e5bc3e7
7e7c9d1
eab2a53
27d765d
6b04a2a
6e28b6d
854cf1c
cd5f285
4a27f20
1cc1685
58e5204
9485942
6381b2e
62f7d2c
2f9efe1
8227806
b5ee959
d89bed9
110cf9d
ecf01d0
0b1ba17
a01fbdb
e5d4e09
321e756
08b5128
ce13ef5
8c3c6a6
6f1a629
b5d85d5
b47c9c7
933dfcb
b3ebfca
b7abd0b
a607824
87d943a
4ef0725
39beca0
cfe83c1
38f9126
3b1ae0a
e67cb37
41ab36e
bb269f3
6a1f76f
af7a880
71d9cde
bc1ab78
7625da9
ee31ce1
f2738fa
317396f
e46d583
ba9ff09
08190af
71a82b4
3ab992d
f8766c5
660ba72
b5426a8
1d17065
d7d8e07
38fac50
c0a74cf
b0d028a
378cdb5
5efc78c
1255d8e
423d620
22890c0
e52fd05
4b006bd
7ab61f7
49446f6
9cb6018
28f303e
241738c
552989a
bcc015a
fc7e60b
401ec4c
4379c7b
b834c05
3e2c80c
fd4eec6
07f1765
0ef0f3d
b687b10
25bc694
c3f8fbd
fff73f2
8d7e9e2
435f0fd
856e203
0ed1f5e
55d56c8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -248,6 +248,9 @@ impl Scalar52 { | |
|
|
||
| // subtract l if the sum is >= l | ||
| proof { lemma_l_value_properties(&constants::L, &sum); } | ||
| assume(to_nat(&sum.limbs) < 2 * group_order()); | ||
| assert(group_order() > to_nat(&sum.limbs) - group_order() >= -group_order()); | ||
| proof{lemma_l_equals_group_order();} | ||
| let result = Scalar52::sub(&sum, &constants::L); | ||
| assume(to_nat(&result.limbs) == (to_nat(&a.limbs) + to_nat(&b.limbs)) % group_order()); | ||
| result | ||
|
|
@@ -259,44 +262,96 @@ impl Scalar52 { | |
| requires | ||
| limbs_bounded(a), | ||
| limbs_bounded(b), | ||
| // Without the following condition, all we can prove is something like: | ||
| // to_nat(&a.limbs) >= to_nat(&b.limbs) ==> to_nat(&s.limbs) == to_nat(&a.limbs) - to_nat(&b.limbs), | ||
| // to_nat(&a.limbs) < to_nat(&b.limbs) ==> to_nat(&s.limbs) == (to_nat(&a.limbs) - to_nat(&b.limbs) + pow2(260) + group_order()) % (pow2(260) as int), | ||
| // In the 2nd case, `sub` doesn't always do subtraction mod group_order | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It took me several tries to get the spec right |
||
| -group_order() <= to_nat(&a.limbs) - to_nat(&b.limbs) < group_order(), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How come this is necessary though?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Also There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In that case, I'd consider relaxing this requirement, but changing ensures to result limbs are bounded, but may represent a value greater than the order, in which case you have to take mod p on the left too.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The weird thing about sub is that isn't always true. If And then if And mod group_order, we get Here's a test demonstrating this: https://github.com/Beneficial-AI-Foundation/curve25519-dalek/tree/sub_test |
||
| ensures | ||
| to_nat(&s.limbs) == (to_nat(&a.limbs) + group_order() - to_nat(&b.limbs)) % (group_order() as int) | ||
| to_nat(&s.limbs) == (to_nat(&a.limbs) - to_nat(&b.limbs)) % (group_order() as int), | ||
| limbs_bounded(&s), | ||
| { | ||
| let mut difference = Scalar52 { limbs: [0u64, 0u64, 0u64, 0u64, 0u64] }; | ||
| proof { assert(1u64 << 52 > 0) by (bit_vector);} | ||
| let mask = (1u64 << 52) - 1; | ||
|
|
||
| // a - b | ||
| let mut borrow: u64 = 0; | ||
| assert(seq_u64_to_nat(a.limbs@.subrange(0, 0 as int)) - seq_u64_to_nat(b.limbs@.subrange(0, 0 as int )) == | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've moved most of the proof of |
||
| seq_u64_to_nat(difference.limbs@.subrange(0, 0 as int ))); | ||
| assert( (borrow >> 63) == 0 ) by (bit_vector) | ||
| requires borrow == 0; | ||
| assert(seq_u64_to_nat(a.limbs@.subrange(0, 0 as int)) - seq_u64_to_nat(b.limbs@.subrange(0, 0 as int )) == | ||
| seq_u64_to_nat(difference.limbs@.subrange(0, 0 as int )) - (borrow >> 63) * pow2((52 * (0) as nat))); | ||
| for i in 0..5 | ||
| invariant | ||
| limbs_bounded(b), | ||
| limbs_bounded(a), | ||
| forall|j: int| 0 <= j < i ==> difference.limbs[j] < (1u64 << 52), | ||
| mask == (1u64 << 52) - 1, | ||
| seq_u64_to_nat(a.limbs@.subrange(0, i as int)) - seq_u64_to_nat(b.limbs@.subrange(0, i as int )) == | ||
| seq_u64_to_nat(difference.limbs@.subrange(0, i as int )) - (borrow >> 63) * pow2((52 * (i) as nat)) | ||
| { | ||
| proof { assert ((borrow >> 63) < 2) by (bit_vector); } | ||
| let ghost old_borrow = borrow; | ||
| borrow = a.limbs[i].wrapping_sub(b.limbs[i] + (borrow >> 63)); | ||
| let ghost difference_loop1_start = difference; | ||
| difference.limbs[i] = borrow & mask; | ||
| assert(difference_loop1_start.limbs@.subrange(0, i as int) == difference.limbs@.subrange(0, i as int)); | ||
| assert( | ||
| seq_u64_to_nat(a.limbs@.subrange(0, i as int)) - seq_u64_to_nat(b.limbs@.subrange(0, i as int )) == | ||
| seq_u64_to_nat(difference_loop1_start.limbs@.subrange(0, i as int )) - (old_borrow >> 63) * pow2((52 * (i) as nat))); | ||
| proof{ | ||
| lemma_sub_loop1_invariant(difference, borrow, i, a, b, old_borrow, mask, difference_loop1_start); | ||
| } | ||
| proof { lemma_borrow_and_mask_bounded(borrow, mask); } | ||
| } | ||
|
|
||
| assert(seq_u64_to_nat(a.limbs@.subrange(0, 5 as int)) - seq_u64_to_nat(b.limbs@.subrange(0, 5 as int )) == | ||
| seq_u64_to_nat(difference.limbs@.subrange(0, 5 as int )) - (borrow >> 63) * pow2((52 * (5) as nat)) ); | ||
| // conditionally add l if the difference is negative | ||
| assert(borrow >> 63 == 1 || borrow >> 63 == 0) by (bit_vector); | ||
| let mut carry: u64 = 0; | ||
| let ghost difference_after_loop1 = difference; | ||
| assert(seq_u64_to_nat(difference_after_loop1.limbs@.subrange(0, 0 as int)) == 0); | ||
| assert(seq_u64_to_nat(constants::L.limbs@.subrange(0, 0 as int)) == 0); | ||
| assert(seq_u64_to_nat(difference.limbs@.subrange(0, 0 as int)) == 0); | ||
| assert(carry >> 52 == 0) by (bit_vector) | ||
| requires carry == 0; | ||
| for i in 0..5 | ||
| invariant | ||
| forall|j: int| 0 <= j < 5 ==> difference.limbs[j] < (1u64 << 52), // from first loop | ||
| forall|j: int| i <= j < 5 ==> difference.limbs[j] == difference_after_loop1.limbs[j], | ||
| mask == (1u64 << 52) - 1, | ||
| i == 0 ==> carry == 0, | ||
| i >= 1 ==> (carry >> 52) < 2, | ||
| (i >=1 && borrow >> 63 == 0) ==> carry == difference.limbs[i-1], | ||
| borrow >> 63 == 0 ==> difference_after_loop1 == difference, | ||
| borrow >> 63 == 1 ==> | ||
| seq_u64_to_nat(difference_after_loop1.limbs@.subrange(0, i as int)) + seq_u64_to_nat(constants::L.limbs@.subrange(0, i as int)) == | ||
| seq_u64_to_nat(difference.limbs@.subrange(0, i as int)) + (carry >> 52) * pow2(52 * i as nat) | ||
|
|
||
| { | ||
| let ghost old_carry = carry; | ||
| let underflow = Choice::from((borrow >> 63) as u8); | ||
| let addend = select(&0, &constants::L.limbs[i], underflow); | ||
| if borrow >> 63 == 0 { | ||
| assert(addend == 0); | ||
| } | ||
| if borrow >> 63 == 1 { | ||
| assert(addend == constants::L.limbs[i as int]); | ||
| } | ||
| proof {lemma_scalar_subtract_no_overflow(carry, difference.limbs[i as int], addend, i as u32, &constants::L);} | ||
| carry = (carry >> 52) + difference.limbs[i] + addend; | ||
| let ghost difference_loop2_start = difference; | ||
| difference.limbs[i] = carry & mask; | ||
| proof { lemma_carry_bounded_after_mask(carry, mask); } | ||
| proof { | ||
| lemma_carry_bounded_after_mask(carry, mask); | ||
| assert(difference_loop2_start.limbs@.subrange(0, i as int) == difference.limbs@.subrange(0, i as int)); | ||
| lemma_sub_loop2_invariant(difference, i, a, b, mask, difference_after_loop1, difference_loop2_start, carry, old_carry, addend, borrow); | ||
| } | ||
| } | ||
| assume(to_nat(&difference.limbs) == (to_nat(&a.limbs) + group_order() - to_nat(&b.limbs)) % (group_order() as int)); | ||
| proof { lemma_sub_correct_after_loops(difference, carry, a, b, difference_after_loop1, borrow);} | ||
| difference | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added this assume in
addso it can callsub. I think this can be propagated back to become another precondition foraddThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this a tautology based on types?
to_natreturns anat, which is always>= 0There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed