Skip to content
This repository was archived by the owner on Jan 3, 2024. It is now read-only.

Commit a6d9d05

Browse files
author
Suphanat Chunhapanya
authored
Fix mod_final_25519 (cloudflare#129)
1 parent 2d86264 commit a6d9d05

File tree

2 files changed

+56
-1
lines changed

2 files changed

+56
-1
lines changed

src/crypto/x25519/mod.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ use std::str::FromStr;
1616
#[cfg(not(target_arch = "arm"))]
1717
use ring::rand::*;
1818

19+
const MASK_63BITS: u128 = 0x7fff_ffff_ffff_ffff;
20+
const MASK_64BITS: u128 = 0xffff_ffff_ffff_ffff;
21+
1922
#[cfg(target_arch = "arm")]
2023
#[allow(non_snake_case)]
2124
pub mod SystemRandom {
@@ -537,13 +540,38 @@ fn mod_final_25519(x: Felem) -> Felem {
537540
let mut acc3 = u128::from(x.0[3]);
538541

539542
let mut top = acc3 >> 63;
540-
acc3 &= 0x7fff_ffff_ffff_ffff;
543+
acc3 &= MASK_63BITS;
544+
top = top.wrapping_mul(19);
545+
acc0 = acc0.wrapping_add(top);
546+
acc1 = acc1.wrapping_add(acc0 >> 64);
547+
acc2 = acc2.wrapping_add(acc1 >> 64);
548+
acc3 = acc3.wrapping_add(acc2 >> 64);
549+
550+
// Mask
551+
acc0 &= MASK_64BITS;
552+
acc1 &= MASK_64BITS;
553+
acc2 &= MASK_64BITS;
554+
acc3 &= MASK_64BITS;
555+
556+
// At this point, acc{0-3} is in the range between 0 and 2^255 + 18, inclusively. It's not
557+
// under 2^255 - 19 yet. So we are doing another round of modulo operation.
541558

559+
top = acc0.wrapping_add(19) >> 64;
560+
top = acc1.wrapping_add(top) >> 64;
561+
top = acc2.wrapping_add(top) >> 64;
562+
top = acc3.wrapping_add(top) >> 63;
542563
top = top.wrapping_mul(19);
564+
565+
// top is 19 if acc{0-3} is between 2^255 - 19 and 2^255 + 18, inclusively. Otherwise, it's
566+
// zero.
567+
543568
acc0 = acc0.wrapping_add(top);
544569
acc1 = acc1.wrapping_add(acc0 >> 64);
545570
acc2 = acc2.wrapping_add(acc1 >> 64);
546571
acc3 = acc3.wrapping_add(acc2 >> 64);
572+
acc3 &= MASK_63BITS;
573+
574+
// Now acc{0-3} is between 0 and 2^255 - 20, inclusively.
547575

548576
Felem([acc0 as u64, acc1 as u64, acc2 as u64, acc3 as u64])
549577
}

src/crypto/x25519/tests.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,33 @@ mod tests {
3333
}
3434
}
3535

36+
#[test]
37+
fn x25519_mod_final_test() {
38+
let max = Felem([
39+
0xffff_ffff_ffff_ffec,
40+
0xffff_ffff_ffff_ffff,
41+
0xffff_ffff_ffff_ffff,
42+
0x7fff_ffff_ffff_ffff,
43+
]);
44+
45+
let zero = Felem([
46+
0x0000_0000_0000_0000,
47+
0x0000_0000_0000_0000,
48+
0x0000_0000_0000_0000,
49+
0x0000_0000_0000_0000,
50+
]);
51+
52+
let one = Felem([
53+
0x0000_0000_0000_0001,
54+
0x0000_0000_0000_0000,
55+
0x0000_0000_0000_0000,
56+
0x0000_0000_0000_0000,
57+
]);
58+
59+
assert_eq!(mod_final_25519(max).0, max.0);
60+
assert_eq!(mod_final_25519(max + one).0, zero.0);
61+
}
62+
3663
#[test]
3764
fn x25519_test_vectors() {
3865
let base: [u8; 32] = [

0 commit comments

Comments
 (0)