Skip to content

Commit 37e9cdf

Browse files
committed
[WIP] Scalar::div_by_2
1 parent 1ad4603 commit 37e9cdf

File tree

3 files changed

+73
-10
lines changed

3 files changed

+73
-10
lines changed

curve25519-dalek/src/backend/serial/u32/scalar.rs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -197,15 +197,33 @@ impl Scalar29 {
197197
}
198198

199199
// conditionally add l if the difference is negative
200+
difference.conditional_add_l(Choice::from((borrow >> 31) as u8));
201+
difference
202+
}
203+
204+
pub(crate) fn conditional_add_l(&mut self, condition: Choice) -> u32 {
200205
let mut carry: u32 = 0;
206+
let mask = (1u32 << 29) - 1;
207+
201208
for i in 0..9 {
202-
let underflow = Choice::from((borrow >> 31) as u8);
203-
let addend = u32::conditional_select(&0, &constants::L[i], underflow);
204-
carry = (carry >> 29) + difference[i] + addend;
205-
difference[i] = carry & mask;
209+
let addend = u32::conditional_select(&0, &constants::L[i], condition);
210+
carry = (carry >> 29) + self[i] + addend;
211+
self[i] = carry & mask;
206212
}
213+
carry
214+
}
207215

208-
difference
216+
/// Compute a raw in-place carrying right shift over the limbs.
217+
#[inline(always)]
218+
pub(crate) fn shr1_assign(&mut self) -> u32 {
219+
let mut carry: u32 = 0;
220+
for i in (0..9).rev() {
221+
let limb = self[i];
222+
let next_carry = limb & 1;
223+
self[i] = (limb >> 1) | (carry << 28);
224+
carry = next_carry;
225+
}
226+
carry
209227
}
210228

211229
/// Compute `a * b`.

curve25519-dalek/src/backend/serial/u64/scalar.rs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,15 +186,34 @@ impl Scalar52 {
186186
}
187187

188188
// conditionally add l if the difference is negative
189+
difference.conditional_add_l(Choice::from((borrow >> 63) as u8));
190+
difference
191+
}
192+
193+
pub(crate) fn conditional_add_l(&mut self, condition: Choice) -> u64 {
189194
let mut carry: u64 = 0;
195+
let mask = (1u64 << 52) - 1;
196+
190197
for i in 0..5 {
191-
let underflow = Choice::from((borrow >> 63) as u8);
192-
let addend = u64::conditional_select(&0, &constants::L[i], underflow);
193-
carry = (carry >> 52) + difference[i] + addend;
194-
difference[i] = carry & mask;
198+
let addend = u64::conditional_select(&0, &constants::L[i], condition);
199+
carry = (carry >> 52) + self[i] + addend;
200+
self[i] = carry & mask;
195201
}
196202

197-
difference
203+
carry
204+
}
205+
206+
/// Compute a raw in-place carrying right shift over the limbs.
207+
#[inline(always)]
208+
pub(crate) fn shr1_assign(&mut self) -> u64 {
209+
let mut carry: u64 = 0;
210+
for i in (0..5).rev() {
211+
let limb = self[i];
212+
let next_carry = limb & 1;
213+
self[i] = (limb >> 1) | (carry << 51);
214+
carry = next_carry;
215+
}
216+
carry
198217
}
199218

200219
/// Compute `a * b`

curve25519-dalek/src/scalar.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,22 @@ impl Scalar {
831831
ret
832832
}
833833

834+
/// Compute `b` such that `b + b = a mod modulus`.
835+
pub fn div_by_2(&self) -> Self {
836+
// We are looking for such `b` that `b + b = a mod modulus`.
837+
// Two possibilities:
838+
// - if `a` is even, we can just divide by 2;
839+
// - if `a` is odd, we divide `(a + modulus)` by 2.
840+
let is_odd = Choice::from(self.as_bytes()[0] & 1);
841+
let mut scalar = self.unpack();
842+
scalar.conditional_add_l(is_odd);
843+
844+
// TODO(tarcieri): propagate carry
845+
let _carry = scalar.shr1_assign();
846+
scalar.pack()
847+
}
848+
849+
834850
/// Get the bits of the scalar, in little-endian order
835851
pub(crate) fn bits_le(&self) -> impl DoubleEndedIterator<Item = bool> + '_ {
836852
(0..256).map(|i| {
@@ -1677,6 +1693,16 @@ pub(crate) mod test {
16771693
}
16781694
}
16791695

1696+
#[test]
1697+
fn div_by_2() {
1698+
for i in 0u64..32 {
1699+
let scalar = Scalar::from(i);
1700+
let double = scalar.double();
1701+
let dividend = double.div_by_2();
1702+
assert_eq!(scalar, dividend);
1703+
}
1704+
}
1705+
16801706
#[test]
16811707
fn reduce() {
16821708
let biggest = Scalar::from_bytes_mod_order([0xff; 32]);

0 commit comments

Comments
 (0)