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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
//! # ic-ec — elliptic-curve cryptography
//!
//! Curve25519 in two guises:
//!
//! * [`X25519`] — RFC 7748 key agreement.
//! * [`Ed25519`] — RFC 8032 signatures.
//!
//! Both are built on a shared constant-time field implementation
//! (`field::Fe`) with 51-bit limbs, and on x86-64 CPUs with BMI2 and ADX on a
//! four-limb field (`fe64::Fe64`) whose multiplication is `MULX`/`ADX`
//! assembly. The second is chosen at run time, once per operation; the first
//! is the fallback and the reference the second is tested against.
//!
//! ```
//! # #[cfg(not(ic_approved_only))]
//! # fn main() -> ic_core::Result<()> {
//! use ic_ec::X25519;
//! use ic_core::traits::KeyAgreement;
//!
//! let alice_sk = [0x11u8; 32];
//! let bob_sk = [0x22u8; 32];
//! let (mut alice_pk, mut bob_pk) = ([0u8; 32], [0u8; 32]);
//! X25519::public_key(&alice_sk, &mut alice_pk)?;
//! X25519::public_key(&bob_sk, &mut bob_pk)?;
//!
//! let (mut s1, mut s2) = ([0u8; 32], [0u8; 32]);
//! X25519::agree(&alice_sk, &bob_pk, &mut s1)?;
//! X25519::agree(&bob_sk, &alice_pk, &mut s2)?;
//! assert_eq!(s1, s2);
//! # Ok(())
//! # }
//! # #[cfg(ic_approved_only)]
//! # fn main() {}
//! ```
//!
//! ## FIPS position
//!
//! Curve25519 is **not** on the FIPS 186-5 / SP 800-186 approved list for
//! signatures, and X25519 is not an approved SP 800-56A scheme. They are here
//! because modern protocols require them, and the ontology marks them
//! accordingly so `ic-fips` blocks them in approved mode, and the
//! `ic_approved_only` cfg leaves them out of the build. The approved curves
//! are here too: ECDSA and ECDH over P-256, P-384 and P-521, in [`p256`],
//! [`p384`] and [`p521`].
// `deny` rather than `forbid`, so that the x86-64 assembly can be allowed it
// and nothing else: `fe64` and `f51x4` for Curve25519, `avx512` to ask the
// CPU, and `nist::p256_x86`, `nist::p384_x86`, the generated
// `nist::p256_x86_point`, `nist::p384_x86_point`, `nist::mont_x86` and
// `nist::ifma_kernels`, and `nist::ifma`, for P-256 and P-384. Each is
// `asm!` and so `unsafe` by construction; everywhere else in this crate
// `unsafe` is a compile error.
// Each `not(ic_approved_only)` below is an algorithm FIPS approved mode does
// not permit, left out of that build; see `ic_core::APPROVED_ONLY`.
// GF(2^255 - 19). Five 51-bit limbs where a 64x64 multiply is cheap; ten limbs
// of 26 and 25 bits on 32-bit RISC-V, where 128-bit arithmetic compiles to
// branches on secret carries. `--cfg ic_limb32` selects the second anywhere, so
// the Curve25519 vectors can be run against it on a host.
// Compiled beside the five-limb field under test, to be compared with it.
// GF(2^255 - 19) in four 64-bit limbs, for x86-64 CPUs with BMI2 and ADX,
// selected at run time; see `field_ops::dispatch!`. Not under `ic_limb32`,
// whose purpose is to run the curve vectors against the ten-limb field, nor
// under `ic_ec_portable`, which runs everything on the portable field.
pub
// Four field elements at once on AVX-512 IFMA, and the Edwards operations on
// them; selected at run time where the CPU has it. Same conditions as `fe64`,
// which it converts through.
// Its unsafe functions are `#[target_feature]` leaves, each a few lines of
// IFMA asm, whose one contract -- the CPU has AVX-512 IFMA -- is the
// function's own and is discharged once, by the `Ifma` token. A separate
// `unsafe` block around each of the 149 operations inside them would restate
// that contract and add nothing; the rest of the crate keeps the lint.
pub
// Whether the CPU runs AVX-512 IFMA, for `f51x4` and `nist::ifma`.
pub
pub use ;
pub use ;
pub use ;
pub use X25519;
/// The implementation P-256's and P-384's scalar multiplications run on here.
///
/// A published vector passes whichever implementation runs, so it cannot tell
/// which one did; this can. P-521 runs the generic field everywhere.
/// Which [`NistBackend`] this CPU and build run, chosen at run time on the
/// CPU's features alone; `--cfg ic_no_avx512` takes `Ifma` away.
/// The implementation of GF(2^255 - 19) that X25519 and Ed25519 run on here.
///
/// A published vector passes whichever implementation runs, so it cannot tell
/// which one did; this can.
/// Which [`Curve25519Backend`] this CPU and build run, chosen at run time on
/// the CPU's features alone.
/// Digest widths ECDSA's `verify_prehash` accepts.
pub use PREHASH_LENS;
/// The narrowest digest ECDSA's `verify_prehash` accepts on a curve.
pub use min_prehash_len;
/// Build every precomputed table now, rather than on first use.
///
/// Under `std`, the generator tables for P-256, P-384 and P-521 and the
/// Ed25519 basepoint tables are built the first time an operation needs them:
/// about one scalar multiplication per curve, a few hundred microseconds in
/// all on a host. They live in statics, so building them allocates nothing
/// whenever it happens. What this changes is *when* the time is spent: a
/// caller that wants its first handshake to cost what every later one does can
/// pay it at start-up instead.
///
/// Safe to call more than once and from several threads: the work is done
/// once, and a second caller waits for the first. Under `no_std` there are no
/// tables, and this does nothing.
/// Ontology identifiers for the schemes implemented here.
pub const EC_IDS: & = &;