cnfy 0.1.2

Zero-dependency cryptographic primitives for Bitcoin — U256 arithmetic and secp256k1 curve operations
Documentation
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
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
# Security Reference

This document maps every cnfy algorithm to its timing behavior, catalogs known
attack vectors against ECC implementations, and identifies the constant-time
alternative for each operation. Users can choose the right tool for the right
job: **default** when operating on public data (speed), **constant-time**
(`--features ct`) when operating on secret data (security).

---

## Table of Contents

- [Algorithm Timing Properties]#algorithm-timing-properties
  - [cnfy-uint]#cnfy-uint
  - [cnfy-secp256k1]#cnfy-secp256k1
  - [Feature Flags]#feature-flags
- [Known Attacks on ECC Implementations]#known-attacks-on-ecc-implementations
  - [Timing Attacks]#timing-attacks
  - [Cache-Timing Attacks]#cache-timing-attacks
  - [EM Emanation Attacks]#em-emanation-attacks
  - [Power Analysis Attacks]#power-analysis-attacks
  - [Fault Injection Attacks]#fault-injection-attacks
  - [Lattice Attacks on Biased Nonces]#lattice-attacks-on-biased-nonces
  - [Supply Chain Attacks]#supply-chain-attacks
  - [Implementation Bugs]#implementation-bugs
- [Modular Inversion Algorithm Comparison]#modular-inversion-algorithm-comparison
- [Recommendations by Use Case]#recommendations-by-use-case
- [Library Comparison]#library-comparison
- [References]#references

---

## Algorithm Timing Properties

### cnfy-uint

Operations with a **Feature** column entry have both default and constant-time variants.
Granular feature flags switch individual dispatchers to the constant-time path at compile
time. Default (no feature flags) provides maximum performance.

| Operation | Method | Timing | Feature | `--features ct` variant | Default source | What leaks (default) | Severity |
|-----------|--------|--------|---------|--------------------------|----------------|----------------------|----------|
| `add_mod` | conditional subtract | **default/CT** | `ct-field` | `add_mod_ct`: branchless `ct_select` (3.75 ns) | 3 branches on carry/borrow/comparison (1.93 ns) | Which of 3 reduction paths; field element magnitude | Medium |
| `sub_mod` | conditional add | **default/CT** | `ct-field` | `sub_mod_ct`: branchless `ct_select` (2.92 ns) | single `match` on borrow (1.85 ns) | Whether self < other (if compiler branches) | Low |
| `mul_mod` dispatch | sparse vs KnuthD | CT (secp256k1) || N/A (branch on public modulus structure) | N/A | Nothing for secp256k1 (branch outcome is fixed) | None |
| `mul_mod_sparse` | fused multiply+reduce | **default/CT** | `ct-field` | `mul_mod_sparse_ct`: always executes round 2, branchless final reduction (15.42 ns) | `if overflow == 0` early return; final comparison (11.89 ns) | Product magnitude (2-3 code paths) | Medium |
| `square_mod_sparse` | fused square+reduce | **default/CT** | `ct-field` | `square_mod_sparse_ct`: same pattern as mul_mod_sparse_ct (12.25 ns) | same as mul_mod_sparse (8.21 ns) | Same as mul_mod_sparse | Medium |
| `sparse_reduce` (U512) | folding reduction | **default/CT** | `ct-field` | `sparse_reduce_ct`: always executes round 2, branchless ct_select (7.39 ns) | `if overflow == 0` early return (3.66 ns) | Product magnitude | Medium |
| `modulo` | subtraction | **default/CT** | `ct-field` | `modulo_ct`: 3 branchless conditional subs | variable iteration count (0-2) | How far above modulus the residue lands | Medium |
| `mod_inv` | extended GCD / divsteps | **default/CT** | `ct-inv` | `mod_inv_ct`: SafeGCD, 12x62 Bernstein-Yang divsteps (8.69 µs) | Lehmer GCD, variable iterations (802 ns) | Full GCD trajectory; structural info about input | **High** |
| `pow_mod` | square-and-multiply | **default/CT** | `ct-pow` | `pow_mod_ct`: always 256 iters, unconditional mul + ct_select (11.04 µs) | loop count = `bit_len(exp)`; per-bit conditional multiply (10.25 µs) | Exponent bits (safe when exp is public, e.g. P-2) | Context-dependent |
| `div_u256` (KnuthD) | multi-precision division | **default only** ||| variable iteration count | Quotient structure | Medium |

### cnfy-secp256k1

| Operation | Method | Timing | Feature | `--features ct` variant | Default source | What leaks (default) | Severity |
|-----------|--------|--------|---------|--------------------------|----------------|----------------------|----------|
| `add_affine` / `add` | madd-2008-g formula | default/CT (inherited) | `ct-field` | inherits CT field ops | no own branches; inherits field op timing | Intermediate coordinate magnitudes | Medium |
| `double` | dbl-2009-l formula | default/CT (inherited) | `ct-field` | inherits CT field ops | no own branches; inherits field op timing | Intermediate coordinate magnitudes | Medium |
| `to_public_key` | Jacobian to affine | **default/CT** | `ct-inv` | inherits CT `mod_inv` (SafeGCD) | `mod_inv` on Z coordinate | Z-coordinate structure (derived from scalar) | **High** |
| Scalar mul (comb) | `into_jacobian_point` | **default/CT** | `ct-scalar` | CT: 4-bit signed comb with Booth recoding, 8-entry CT scan per column (15.9 µs) | `if v != 0` skips zero columns; secret-indexed table lookup (5.50 µs) | 4-bit scalar nybbles; which columns are zero; cache-timing on table index | **Critical** |
| `first_nonzero_point` | comb startup | **default only** || — (only used in default accumulation path) | loop until first nonzero column | Position of MSB byte of scalar | **High** |

### Feature Flags

Granular features allow enabling only the constant-time operations you need, minimizing
performance overhead. Each feature activates its constant-time dispatcher at compile time
with zero overhead to the default path when disabled.

| Feature | Crate | What it enables | Dependencies | Overhead |
|---------|-------|----------------|--------------|----------|
| `ct-field` | cnfy-uint | `add_mod`, `sub_mod`, `mul_mod_sparse`, `square_mod_sparse`, `sparse_reduce`, `modulo` || 30-95% per op |
| `ct-inv` | cnfy-uint | `mod_inv` (SafeGCD, Bernstein-Yang divsteps) | `ct-field` | 10.8x vs Lehmer |
| `ct-pow` | cnfy-uint | `pow_mod` (always 256 iters, ct_select) | `ct-field` | 8% |
| `ct-scalar` | cnfy-secp256k1 | `into_jacobian_point` (4-bit signed comb, 8-entry CT scan, 65-col loop) | `ct-field` | 2.9x |
| `ct` | both | All of the above (backward compatible umbrella) | all | varies |

**Usage examples:**

```bash
# Full CT (ECDSA signing ready)
cargo build --features ct

# Only CT field arithmetic (cheapest, still protects intermediate values)
cargo build --features ct-field

# CT scalar multiplication + field (for key generation)
cargo build --features ct-scalar

# CT modular inversion only (e.g. for Jacobian→affine conversion)
cargo build --features ct-inv
```

---

## Known Attacks on ECC Implementations

This section catalogs real-world attacks that have broken production
cryptographic systems. Each demonstrates why specific defensive measures
matter when choosing or building an ECC library.

### Timing Attacks

Measure execution time differences to infer secret-dependent code paths.

| CVE / Paper | Target | Side Channel | Impact | Year |
|-------------|--------|-------------|--------|------|
| CVE-2024-13176 | OpenSSL P-521 ECDSA | ~300ns timing difference when top word of inverted nonce is zero | Private key recovery via lattice reduction | 2025 |
| CVE-2020-13162 | OpenSSL P-256 ECDSA | Missing `BN_FLG_CONSTTIME` on nonces; non-CT `BN_mod_inverse` path | Cache-timing key recovery | 2020 |
| Bug 1623116 | Mozilla NSS P-384/P-521 | Side-channel vulnerable modular inversion | Key recovery | 2020 |
| Minerva (CVE-2024-23342) | libgcrypt, wolfSSL, MatrixSSL, SunEC, python-ecdsa | Nonce bit-length leak during `k*G` | Key recovery from 500-2100 signatures | 2020 |
| CVE-2019-15809 | Athena/Atmel FIPS smart cards | Nonce bit-length timing leak | Key recovery from hundreds of signatures | 2019 |

**Defense**: Constant-time field arithmetic (branchless conditional subtract
via bitmask), constant-time modular inversion (SafeGCD or Fermat), constant-time
scalar multiplication (fixed-window with dummy ops).

### Cache-Timing Attacks

Monitor CPU cache behavior (FLUSH+RELOAD, PRIME+PROBE, port contention) to
observe which code paths and memory addresses a victim accesses during signing.

| CVE / Paper | Target | Side Channel | Impact | Year |
|-------------|--------|-------------|--------|------|
| "Ooh Aah" (Benger et al.) | OpenSSL secp256k1 | FLUSH+RELOAD on scalar mul | Full key from ~200 signatures | 2014 |
| CVE-2014-0076 | OpenSSL ECDSA | FLUSH+RELOAD on Montgomery ladder swap | Full key from ~2400 traces | 2014 |
| CVE-2018-5407 (PortSmash) | OpenSSL P-384 | Port contention on SMT/Hyper-Threading | Full P-384 key from TLS server | 2018 |
| LadderLeak | OpenSSL P-192/P-256/secp256k1 | FLUSH+RELOAD on Montgomery ladder | Key recovery from < 1 bit/signature | 2020 |

**Defense**: No secret-dependent memory accesses. Fixed-window scalar
multiplication with constant-time table lookups (touch all entries, select
via bitmask). Avoid wNAF representations that leak Hamming weight. Disable
SMT where cryptographic operations occur.

### EM Emanation Attacks

Measure EM radiation emitted during computation. Can work at distance (across
a wall) and breaks implementations that are "constant-time" in software.

| Paper | Target | Method | Impact | Year |
|-------|--------|--------|--------|------|
| Genkin et al. | OpenSSL/CoreBitcoin on iOS | $2 magnetic probe near phone | Full ECDSA key from mobile device | 2016 |
| Genkin et al. | OpenSSL on PC | EM emanation from adjacent room | ECDH key extraction through a wall | 2016 |
| Nonce@Once | OpenSSL, Libgcrypt, HACL* | Single EM trace on cswap | 100% success, full nonce from 1 trace | 2021 |

**Key insight**: The Nonce@Once attack broke multiple supposedly constant-time
implementations (OpenSSL, Libgcrypt, HACL*, curve25519-donna) via
operand-dependent EM leakage in conditional swap operations. Software-only
"constant-time" is insufficient against EM probes.

**Defense**: Scalar and coordinate blinding (randomize intermediate values so
EM traces are uncorrelated with the secret). Hardware-level EM shielding and
noise injection. Randomized projective coordinates.

### Power Analysis Attacks

Measure a device's power consumption during cryptographic operations. Simple
Power Analysis (SPA) reads key bits from a single trace; Differential Power
Analysis (DPA) uses statistics over many traces.

| Paper | Target | Method | Impact | Year |
|-------|--------|--------|--------|------|
| Coron | General double-and-add | SPA on power trace | Entire scalar from 1 trace | 1999 |
| Ark of the ECC | CrypTech FPGA P-256 | Open-source DPA via ChipWhisperer | Full key recovery | 2021 |
| Trezor RDP attack | Trezor One/Model T | Voltage glitching on STM32 | Full seed extraction ($75, 15 min) | 2020 |

**Defense**: Montgomery ladder or always-double-and-add (constant operation
sequence). Randomized projective coordinates. Scalar blinding. Secure elements
with built-in DPA countermeasures.

### Fault Injection Attacks

Deliberately induce computational errors (voltage glitching, clock
manipulation, laser pulses, Rowhammer) during signing. The faulty output
reveals information about the secret key.

| Paper | Target | Method | Impact | Year |
|-------|--------|--------|--------|------|
| Biehl-Meyer-Muller | General ECC | Bit errors during scalar mul | Key recovery via weak-curve DLP | 2000 |
| Blomer-Otto-Seifert | General ECC | Sign change (negate y-coordinate) | Key recovery; point stays on curve | 2006 |
| Degenerate fault | OpenSSL secp256k1 | Instruction skip during point decompression | Single-fault full key recovery | 2019 |
| DFA on RFC 6979 | Deterministic ECDSA | Rowhammer during signing | Lattice-based key recovery | 2017 |

**secp256k1 note**: The degenerate fault attack is *especially devastating*
for secp256k1 (j-invariant = 0) — key recovery reduces to a single field
division after one faulty signature.

**Defense**: Hedged signatures ([draft-irtf-cfrg-det-sigs-with-noise](https://cfrg.github.io/draft-irtf-cfrg-det-sigs-with-noise/draft-irtf-cfrg-det-sigs-with-noise.html)) —
mix fresh randomness into RFC 6979 nonce generation. Verify output point is on
curve after scalar multiplication. Re-verify each signature before releasing it.

### Lattice Attacks on Biased Nonces

If ECDSA nonces have any statistical bias — even a few bits — an attacker
observing enough signatures formulates a Hidden Number Problem (HNP) and
solves it via lattice reduction (LLL/BKZ) to recover the private key.

| Paper | Target | Bias Source | Impact | Year |
|-------|--------|------------|--------|------|
| Biased Nonce Sense | Bitcoin blockchain (secp256k1) | Weak RNGs producing short nonces | Hundreds of real Bitcoin keys recovered | 2019 |
| Polynonce | Bitcoin/Ethereum (secp256k1) | LCG-based nonce generation | Key recovery in ~70ms on laptop | 2023 |
| Sony PS3 | Sony firmware signing | Same nonce `k` reused for every signature | Full firmware signing key published | 2010 |

**Quantitative thresholds** (Breitner & Heninger, 2019): For 256-bit ECDSA,
4 bits of nonce bias = completely broken. Two signatures with 128-bit nonces =
75% key recovery probability. Nonce reuse = instant key recovery from 2
signatures via `d = (s1*z2 - s2*z1) / (s2*r1 - s1*r2) mod n`.

**Defense**: RFC 6979 deterministic nonces (eliminates RNG dependency). Hedged
nonces for fault resistance. Never use LCGs or other weak PRNGs. Validate
nonces are in full range [1, n-1] with uniform distribution.

### Supply Chain Attacks

Compromise the software supply chain — backdoor a dependency, an RNG standard,
or a build process — so downstream users unknowingly ship compromised code.

| Incident | Target | Method | Impact | Year |
|----------|--------|--------|--------|------|
| Dual_EC_DRBG | NIST SP 800-90A / RSA BSAFE | NSA-backdoored RNG standard | All crypto operations compromised | 2004-2014 |
| event-stream | npm / Copay Bitcoin wallet | Social-engineered maintainership | Targeted Bitcoin wallet theft | 2018 |
| CVE-2024-3094 (xz) | xz/liblzma / OpenSSH | 2-year trust-building, backdoor in build | RCE via SSH (caught pre-release) | 2024 |
| SolarWinds SUNBURST | SolarWinds Orion | Build process injection, signed with genuine cert | 18,000+ organizations compromised | 2020 |

**Defense**: Zero third-party dependencies (the cnfy approach). Reproducible
builds. Vendored and audited dependencies if external code is necessary.
CSPRNG from the OS (`getrandom()`) rather than userspace PRNGs.

### Implementation Bugs

Logical errors — missing validations, incorrect algorithms, arithmetic bugs —
that allow attacks without any physical or timing observation.

| CVE | Target | Bug | Impact | Year |
|-----|--------|-----|--------|------|
| CVE-2020-0601 (CurveBall) | Windows CryptoAPI | Generator point not validated in certs | Forge any code-signing or TLS cert | 2020 |
| CVE-2022-21449 (Psychic Signatures) | Java JDK 15-18 | `r=0, s=0` signature not rejected | Universal signature forgery | 2022 |
| CVE-2015-7940 | Bouncy Castle / SunEC | Missing point-on-curve check in ECDH | Full TLS key via invalid curve attack | 2015 |
| CVE-2024-48930 | secp256k1-node (npm) | Missing point validation in compressed key loading | Full key from 11 ECDH sessions | 2024 |

**Defense**: Validate every received point is on the curve (`Y^2 == X^3 + 7`
for secp256k1). Validate signature components `r, s` are in `[1, n-1]`.
Validate generator points match the expected standard. Test against
[Project Wycheproof](https://github.com/google/wycheproof) vectors.

---

## Modular Inversion Algorithm Comparison

| Property | Lehmer GCD (cnfy default) | Bernstein-Yang SafeGCD (cnfy `--features ct`) | Fermat (a^(P-2)) |
|----------|--------------------------|-----------------------------------------------|-------------------|
| **Constant-time** | No | **Yes** | Yes (if exp is public) |
| **GPU-portable** | No (deeply branchy) | No (data-dependent branching) | **Yes** (branchless) |
| **Speed (256-bit field inv)** | **~802 ns** (cnfy benchmark) | ~8,690 ns (cnfy `--features ct-inv`) | ~10,250 ns (cnfy `pow_mod`) |
| **Operations** | Variable (Euclidean steps) | 724 divsteps, batched in groups of 62 = 12 outer iterations | 255 squarings + 14 multiplications = 269 field ops |
| **Why fast/slow** | Fewest total ops; early termination | More iterations but each divstep is cheap (shift+add); batching amortizes big-int work | Each op is a full field multiply; most total work |
| **ECDSA signing impact** | N/A (not constant-time, unsafe for signing) | **25-30% faster signing** vs Fermat (libsecp256k1 data) | Baseline for CT signing |
| **Batch-friendly** | Yes (Montgomery's trick) | Yes (Montgomery's trick) | Yes (Montgomery's trick) |
| **Rust implementations** | cnfy-uint `mod_inv` (default) | cnfy-uint `mod_inv` (`--features ct-inv`), crypto-bigint `SafeGcdInverter`, k256 crate | cnfy-uint `pow_mod` |

### SafeGCD (Bernstein-Yang divsteps) details

The algorithm transforms `(delta, f, g)` per step:
- 1 parity check (LSB of g), 1 sign check (delta), 1 conditional swap, 1 subtraction, 1 right-shift
- All constant-time via masked operations (no branches)
- **Batching**: 62 divsteps computed on low 62 bits (fitting in u64), producing a 2x2 transition matrix applied once to full-width 256-bit values
- **Iteration bound**: 724 divsteps proven sufficient for 256-bit (formally verified in Coq)
- **Outer loop**: ceil(724/62) = 12 iterations, each doing 4 full-width multiply-accumulates

---

## Recommendations by Use Case

### Operations on public data only

When all inputs are public (e.g., adding known generator points, batch
conversions of public keys), there is no side-channel risk. Default
operations are safe and preferred for speed.

| Component | Recommendation | Why |
|-----------|---------------|-----|
| Point addition (public + public) | Use default implementation | No secret data; speed matters |
| Batch inversion (Montgomery) | Use default `mod_inv` | Amortized to ~46 ns/element; no secret |

### ECDSA signing

**All operations touching the private key or nonce must be constant-time.**
A single bit of nonce leakage per signature enables key recovery.

| Component | Current Status | Required | Feature |
|-----------|---------------|----------|---------|
| Scalar multiplication (`k * G`) | **CT available**: 4-bit signed comb, 8-entry CT scan, 65-col loop (15.9 µs) | CT: fixed-window with dummy ops + CT table scan | `ct-scalar` |
| Modular inversion (`k^-1 mod N`) | **CT available**: SafeGCD, Bernstein-Yang divsteps (8.69 µs) | CT: SafeGCD or Fermat | `ct-inv` |
| Field arithmetic (`mul_mod`, `add_mod`) | **CT available**: branchless via `ct_select` | Already implemented; enable `ct-field` feature | `ct-field` |
| Nonce generation | Not yet implemented | Must use RFC 6979 deterministic nonces + hedging ||

**cnfy's position**: With `--features ct`, cnfy now provides constant-time
paths for all arithmetic operations required for ECDSA signing: field ops,
modular inversion (SafeGCD), and scalar multiplication (4-bit signed comb
with Booth recoding and 8-entry CT table lookups). The remaining gap is nonce
generation (RFC 6979), which requires SHA-256 (planned in `cnfy-hash`).

### Key generation

| Component | Current Status | Required | Feature |
|-----------|---------------|----------|---------|
| Scalar multiplication (`secret * G`) | **CT available** (15.9 µs) | CT scalar mul | `ct-scalar` |
| Random scalar sampling | Not yet implemented | CSPRNG + rejection sampling in CT ||

### Input validation (all use cases)

| Check | Required | Prevents |
|-------|----------|----------|
| Point on curve (`Y^2 == X^3 + 7 mod P`) | Every received point | Invalid curve attacks (CVE-2015-7940, CVE-2024-48930) |
| Point not at infinity | Every received point | Degenerate inputs |
| Signature `r, s` in `[1, n-1]` | Every signature verification | Psychic Signatures (CVE-2022-21449) |
| Generator matches standard | Certificate/key file parsing | CurveBall (CVE-2020-0601) |

---

## Library Comparison

This table compares cnfy against production ECC libraries across every attack
category documented above. The goal is transparency: users should pick the
library that matches their threat model, even if that means choosing a
competitor.

**Legend**: Yes = protected, **No** = vulnerable, Partial = some protection,
N/A = feature not implemented / not applicable.

**Note**: The `secp256k1` Rust FFI crate (wrapping the C library) is **no longer
maintained**. Its developers recommend migrating to **k256**. It is included here
for reference since existing projects may still depend on it, but should not be
chosen for new projects.

### Side-channel protection

| Defense | cnfy | secp256k1 (Rust FFI) | libsecp256k1 (C) | k256 (RustCrypto) | ring | OpenSSL |
|---------|------|----------------------|-------------------|--------------------|----- |---------|
| CT scalar multiplication | **Yes** (`ct-scalar`: 4-bit signed comb, Booth recoding, 65-col branchless loop) | Yes (inherits C library) | Yes (fixed-window, CT table scan, unified add/double) | Yes (projective formulas, `subtle` crate CT select) | Yes (BoringSSL nistz256, CT) | Yes (post-2018 fixes, Montgomery ladder with CT swap) |
| CT table lookups | **Yes** (`ct-scalar`: 8-entry linear scan with ct_select per column) | Yes (inherits C library) | Yes (linear scan with CT select) | Yes (`subtle::ConditionallySelectable`) | Yes (CT table access) | Yes (post CVE-2014-0076 fix) |
| CT modular inversion | **Yes** (`ct-inv`: SafeGCD, Bernstein-Yang divsteps) | Yes (inherits C library) | Yes (SafeGCD, Bernstein-Yang divsteps) | Yes (SafeGCD via `crypto-bigint`) | Yes (Fermat inversion) | Partial (CT since CVE-2024-13176 fix; historically vulnerable) |
| CT field arithmetic | **Yes** (`ct-field`: branchless `add_mod`, `sub_mod`, `mul_mod_sparse`, `square_mod_sparse`, `sparse_reduce`, `modulo` via `ct_select`) | Yes (inherits C library) | Yes (branchless, constant memory access) | Yes (branchless via `subtle` crate) | Yes (BoringSSL fiat-crypto, formally verified) | Partial (improved over time; historical CVEs) |
| Scalar blinding | No | No | No | No | No | Yes (optional) |
| Coordinate randomization | No | No | No | No | No | Yes (optional) |

**cnfy's position**: With `--features ct`, cnfy provides constant-time paths
for all core signing operations: field arithmetic (`ct-field`), modular
inversion via SafeGCD (`ct-inv`), and scalar multiplication with 4-bit signed
comb and 8-entry CT table lookups (`ct-scalar`). The default remains the fastest option for
public-data operations. For ECDSA signing, enable `--features ct` (or the
specific granular features needed). The remaining gap for production ECDSA
is nonce generation (RFC 6979), planned for `cnfy-hash`.

### Input validation

| Check | cnfy | secp256k1 (Rust FFI) | libsecp256k1 (C) | k256 | ring | OpenSSL |
|-------|------|----------------------|------------------|------|------|---------|
| Point on curve (Y^2 = X^3 + 7) | Yes (`AffinePoint::is_on_curve`, `new_verified`, `CompressedPoint::y`) | Yes (inherits C library) | Yes (on all public API inputs) | Yes (on deserialization) | Yes | Yes |
| Point at infinity rejected | Yes (`Error::PointAtInfinity`, Z=0 check) | Yes (inherits C library) | Yes | Yes | Yes | Yes |
| Secret key range [1, n-1] | Yes (`SecretKey::is_valid_scalar`, CT comparison) | Yes (inherits C library) | Yes | Yes | Yes | Yes |
| Signature r,s in [1, n-1] | N/A (no ECDSA) | Yes (inherits C library) | Yes | Yes | Yes | Yes |
| Reject (r=0, s=0) signature | N/A (no ECDSA) | Yes (inherits C library) | Yes | Yes | Yes | Yes |

**cnfy's position**: Input validation is thorough. Deserialization paths
(`from_sec1_bytes`, `from_be_bytes`) always validate. Internal constructors
(`new`) skip validation by design — arithmetic on valid inputs produces valid
outputs. This matches the libsecp256k1 and k256 approach.

### Nonce security (ECDSA signing)

| Feature | cnfy | secp256k1 (Rust FFI) | libsecp256k1 (C) | k256 | ring | OpenSSL |
|---------|------|----------------------|------------------|------|------|---------|
| RFC 6979 deterministic nonces | N/A (no ECDSA) | Yes (inherits C library) | Yes (default) | Yes (via `ecdsa` crate) | **No** (random nonces via SystemRandom) | Yes (opt-in since OpenSSL 3.2) |
| Hedged nonces (RFC 6979 + randomness) | N/A | Yes (inherits C library) | Yes (extra entropy parameter) | Yes (RFC 6979 + RNG) | Partial (random-only resists fault injection, but depends on RNG quality) | No |

**ring's position**: ring deliberately uses random nonces instead of RFC 6979.
This protects against fault injection on deterministic signing but creates
dependency on RNG quality. ring mitigates this by requiring `SystemRandom`
(OS CSPRNG), which is the strongest available RNG — but it cannot protect
against a compromised OS entropy source.

### Supply chain and code quality

| Property | cnfy | secp256k1 (Rust FFI) | libsecp256k1 (C) | k256 | ring | OpenSSL |
|----------|------|----------------------|------------------|------|------|---------|
| Third-party dependencies | **0** | ~3 (secp256k1-sys vendors C, cc, libc) | **0** (C library) | ~15 (crypto-bigint, subtle, elliptic-curve, etc.) | ~5 (minimal, mostly internal) | System library (C) |
| `unsafe` code | **None** | Yes (FFI layer to C) | N/A (C) | Minimal (via `subtle` crate) | Yes (assembly, FFI) | N/A (C) |
| Language | Pure Rust | Rust FFI wrapping C | C | Pure Rust | Rust + C/asm | C |
| Formal verification | No | No (inherits C library properties) | No (but exhaustive testing, Coq proof for SafeGCD bounds) | Partial (fiat-crypto for some field ops) | Partial (fiat-crypto, BoringSSL heritage) | No |
| Known ECC CVEs | 0 (new library) | 0 (wrapper layer) | ~1 (timing leak, fixed 2015) | 0 | 0 | 118 total; ~6 ECC-specific |
| Security audit | No | Inherits C library review | Extensively reviewed by Bitcoin Core contributors | Audited as part of RustCrypto ecosystem | Google security team review | Extensively audited; frequent CVEs still found |
| Actively maintained | Yes | **No** (deprecated, migrate to k256) | Yes (Bitcoin Core) | Yes (RustCrypto) | Yes (Google) | Yes (OpenSSL project) |

### Attack-by-attack vulnerability matrix

| Attack | cnfy | secp256k1 (Rust FFI) | libsecp256k1 (C) | k256 | ring | OpenSSL |
|--------|------|----------------------|------------------|------|------|---------|
| **Timing (scalar mul)** | **Protected** (with `ct-scalar`) | Protected | Protected | Protected | Protected | Protected (post-2018) |
| **Timing (mod_inv)** | **Protected** (with `ct-inv`) | Protected (SafeGCD) | Protected (SafeGCD) | Protected (SafeGCD) | Protected (Fermat) | Mostly protected (post-2025) |
| **Timing (field ops)** | **Protected** (with `ct-field`) | Protected | Protected | Protected | Protected | Mostly protected |
| **Cache (table lookup)** | **Protected** (with `ct-scalar`) | Protected (CT scan) | Protected (CT scan) | Protected (`subtle`) | Protected | Protected (post-2014) |
| **Cache (PortSmash/SMT)** | **Protected** (with `ct-scalar`) | Protected | Protected | Protected | Protected | Protected (post-2018) |
| **EM emanation** | Vulnerable | Partially (no blinding) | Partially (no blinding) | Partially (no blinding) | Partially (no blinding) | Partially (optional blinding) |
| **Power analysis (SPA)** | Vulnerable | Partially (no blinding) | Partially (no blinding) | Partially (no blinding) | Partially (no blinding) | Partially (optional blinding) |
| **Fault injection** | N/A (no ECDSA) | Protected (hedged nonces) | Protected (hedged nonces) | Protected (hedged nonces) | Protected (random nonces) | Vulnerable (no hedged nonces) |
| **Biased nonces** | N/A (no ECDSA) | Protected (RFC 6979) | Protected (RFC 6979) | Protected (RFC 6979) | Protected (OS CSPRNG) | Protected (RFC 6979) |
| **Nonce reuse** | N/A (no ECDSA) | Protected (RFC 6979) | Protected (RFC 6979) | Protected (RFC 6979) | Protected (random) | Protected (RFC 6979) |
| **Supply chain** | **Protected** (0 deps) | Low risk (~3 deps, vendors C) | **Protected** (0 deps) | Exposed (~15 deps) | Low risk (~5 deps) | System-level risk |
| **Invalid curve (ECDH)** | Protected (point validation) | Protected | Protected | Protected | Protected | Protected |
| **Signature forgery (r=0,s=0)** | N/A (no ECDSA) | Protected | Protected | Protected | Protected | Protected |

### When to use each library

| Use case | Recommended library | Why |
|----------|-------------------|-----|
| **ECDSA signing (production, Rust)** | k256 or cnfy (`--features ct`) | k256: mature, audited, RFC 6979. cnfy: zero deps, CT (needs SHA-256 for nonces) |
| **ECDSA signing (Rust, existing secp256k1 FFI users)** | k256 (migrate) | secp256k1 Rust FFI is deprecated; k256 is the recommended replacement |
| **ECDSA signing (C/C++)** | libsecp256k1 | Gold standard, formally verified SafeGCD, hedged nonces |
| **High-throughput public-data operations** | cnfy | Fastest field arithmetic, batch operations, zero deps |
| **TLS / general-purpose crypto** | ring or OpenSSL | Broad algorithm support, well-tested |
| **Minimal supply chain risk** | cnfy or libsecp256k1 | Zero third-party dependencies |
| **Embedded / no-std** | cnfy or k256 | Pure Rust, no heap, no-std compatible |

---

## References

**Algorithms**:
- [Bernstein-Yang: "Fast constant-time gcd computation and modular inversion"]https://gcd.cr.yp.to/safegcd-20190413.pdf
- [libsecp256k1 safegcd implementation]https://github.com/bitcoin-core/secp256k1/blob/master/doc/safegcd_implementation.md
- [libsecp256k1 PR #831: SafeGCD inverses]https://github.com/bitcoin-core/secp256k1/pull/831
- [Formal proof of safegcd bounds (Coq)]https://medium.com/blockstream/a-formal-proof-of-safegcd-bounds-695e1735a348
- [Addition chains for ECC inversion]https://briansmith.org/ecc-inversion-addition-chains-01
- [Hedged signatures (draft-irtf-cfrg-det-sigs-with-noise)]https://cfrg.github.io/draft-irtf-cfrg-det-sigs-with-noise/draft-irtf-cfrg-det-sigs-with-noise.html

**Timing and cache attacks**:
- [CVE-2024-13176: OpenSSL P-521 timing leak]https://nvd.nist.gov/vuln/detail/CVE-2024-13176
- [CVE-2019-15809: Athena smart card ECDSA timing]https://nvd.nist.gov/vuln/detail/CVE-2019-15809
- [Minerva: timing attack on ECDSA nonces]https://minerva.crocs.fi.muni.cz/
- ["Ooh Aah... Just a Little Bit" — FLUSH+RELOAD on OpenSSL ECDSA]https://eprint.iacr.org/2014/161.pdf
- [CVE-2018-5407: PortSmash]https://github.com/bbbrumley/portsmash
- [LadderLeak: Breaking ECDSA With Less Than One Bit Of Nonce Leakage]https://eprint.iacr.org/2020/615.pdf

**EM and power analysis**:
- [ECDSA Key Extraction from Mobile Devices via Nonintrusive Physical Side Channels]https://cs-people.bu.edu/tromer/mobilesc/
- [Nonce@Once: Single-Trace EM Attack on Constant-Time ECC]https://faculty.cc.gatech.edu/~genkin/papers/nonceatonce.pdf
- [Ark of the ECC: Open-Source ECDSA Power Analysis]https://eprint.iacr.org/2021/1520

**Fault injection**:
- [Biehl-Meyer-Muller: Differential Fault Attacks on ECC (CRYPTO 2000)]https://link.springer.com/chapter/10.1007/3-540-44598-6_8
- [Blomer-Otto-Seifert: Sign Change Fault Attacks]https://eprint.iacr.org/2004/227
- [Degenerate Fault Attacks on Elliptic Curve Parameters in OpenSSL]https://eprint.iacr.org/2019/400.pdf
- [Attacking Deterministic Signature Schemes using Fault Attacks]https://eprint.iacr.org/2017/1014.pdf

**Lattice attacks and biased nonces**:
- [Biased Nonce Sense: Lattice Attacks on Weak ECDSA in Cryptocurrencies]https://eprint.iacr.org/2019/023.pdf
- [Polynonce: A Novel ECDSA Attack (DEF CON 31)]https://kudelskisecurity.com/research/polynonce-a-tale-of-a-novel-ecdsa-attack-and-bitcoin-tears

**Implementation bugs**:
- [CVE-2020-0601: CurveBall / Windows CryptoAPI]https://unit42.paloaltonetworks.com/threat-brief-windows-cryptoapi-spoofing-vulnerability-cve-2020-0601/
- [CVE-2022-21449: Psychic Signatures in Java]https://neilmadden.blog/2022/04/19/psychic-signatures-in-java/
- [CVE-2015-7940: Invalid Curve Attacks on TLS-ECDH]https://link.springer.com/chapter/10.1007/978-3-319-24174-6_21
- [CVE-2024-48930: secp256k1-node invalid curve attack]https://github.com/advisories/GHSA-584q-6j8j-r5pm
- [Project Wycheproof test vectors]https://github.com/google/wycheproof

**Supply chain**:
- [Dual_EC_DRBG backdoor]https://en.wikipedia.org/wiki/Dual_EC_DRBG
- [event-stream npm attack post-mortem]https://snyk.io/blog/a-post-mortem-of-the-malicious-event-stream-backdoor/
- [CVE-2024-3094: xz Utils backdoor]https://www.crowdstrike.com/en-us/blog/cve-2024-3094-xz-upstream-supply-chain-attack/

**Implementations**:
- [crypto-bigint SafeGcdInverter (Rust)]https://github.com/RustCrypto/crypto-bigint
- [k256: pure Rust secp256k1 with CT inversion]https://docs.rs/k256