1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use crate::{Convenient, Digit, Odd, Prime, Short, Unsigned};
pub struct F4 {}
impl F4 {
pub const DIGIT: Digit = 0x1_0001;
pub const SHORT: Short<1> = Short::from_digit(Self::DIGIT);
pub const PRIME: Prime<1, 0> = Prime(Convenient(Odd(Short::from_digit(Self::DIGIT))));
pub fn minus_one() -> Short<1> {
Short::from(Self::DIGIT - 1)
}
pub fn prime() -> Prime<1, 0> {
Prime(Convenient(Odd(Short::from(Self::DIGIT))))
}
pub fn wrapping_inv<const D: usize, const E: usize> () -> Unsigned<D, E> {
Unsigned::from(Self::DIGIT).wrapping_inv().unwrap()
}
pub fn inv_mod<const D: usize>(p: &Unsigned<D, 0>) -> Odd<D, 0> {
let p_mod_e = p.clone().modulo_prime(&Self::PRIME);
let minus_p_inv_mod_e: Digit = Self::DIGIT - p_mod_e.inverse().canonical_lift().digit();
let numerator: crate::Unsigned<D, 1> =
(p * &Short::<D>::from(minus_p_inv_mod_e))
.to_unsigned::<D, 1>().unwrap()
.wrapping_add(&crate::Unsigned::<D, 1>::from(1));
let inverted_denominator = Self::wrapping_inv();
let d = numerator.wrapping_mul(&inverted_denominator);
Odd(d.to_unsigned().unwrap())
}
}
#[cfg(test)]
mod test {
use super::*;
use hex_literal::hex;
#[test]
fn modular_inverses() {
let p = crate::fixtures::p256();
let p_mod_e = p.modulo_prime(&F4::PRIME);
assert_eq!(p_mod_e.residue(), &Short::<1>::from_slice(&[49818]));
assert_eq!(p_mod_e.canonical_lift().digit(), 49818);
assert_eq!(p_mod_e.inverse().canonical_lift().digit(), 19900);
let minus_p_inv_mod_e = crate::F4::DIGIT - p_mod_e.inverse().canonical_lift().digit();
assert_eq!(minus_p_inv_mod_e, 45637);
let minus_p_inv_mod_e = crate::F4::DIGIT - p_mod_e.inverse().residue().digit();
assert_eq!(minus_p_inv_mod_e, 45637);
let modular_inverse = F4::inv_mod(&p);
assert_eq!(&*modular_inverse.to_bytes(), &hex!("9a6796b73305ab0616980b76d18a61a3a61469efd3614b1518a5ed95cd4c8f1e"));
}
#[test]
#[cfg(feature = "extended-testing")]
fn inv_mod_e() {
let e = F4::DIGIT;
let f4 = F4::PRIME;
for i in 3..e {
let maybe_inverse: Short<1> = Short::<1>::from(i).modulo_prime(&f4).inverse().canonical_lift();
let maybe_one: crate::Long<1> = (f4.as_unsigned() * &maybe_inverse).to_unsigned().unwrap();
let remainder = (maybe_one % f4.as_unsigned()).digit();
assert_eq!(remainder, 0);
}
}
}