Skip to main content

dcrypt_algorithms/ec/k256/
mod.rs

1//! Koblitz secp256k1 Elliptic Curve Primitives
2//!
3//! This module implements secp256k1 elliptic-curve arithmetic.
4//! The curve equation is y² = x³ + 7 over the prime field F_p where:
5//! - p = 2^256 - 2^32 - 977
6//! - The curve order n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
7//!
8//! Selected paths use fixed-iteration or conditional-selection techniques, but
9//! no blanket constant-time claim is made for the module, compiler, or target.
10
11mod constants;
12mod field;
13mod point;
14mod scalar;
15
16pub use constants::{
17    K256_FIELD_ELEMENT_SIZE, K256_KEM_SHARED_SECRET_KDF_OUTPUT_SIZE, K256_POINT_COMPRESSED_SIZE,
18    K256_POINT_UNCOMPRESSED_SIZE, K256_SCALAR_SIZE,
19};
20pub use field::FieldElement;
21pub use point::{Point, PointFormat};
22pub use scalar::Scalar;
23
24use crate::error::{Error, Result};
25use crate::hash::sha2::Sha256;
26use crate::kdf::hkdf::Hkdf;
27use crate::kdf::KeyDerivationFunction as KdfTrait;
28use dcrypt_internal::random::{try_fill_bytes_zeroing_on_error, CryptoRng, RngCore};
29use dcrypt_internal::zeroing::Zeroizing;
30
31/// SECP256K1 curve parameters (base point G)
32struct Secp256k1Params {
33    g_x: [u8; 32],
34    g_y: [u8; 32],
35}
36
37const SECP256K1: Secp256k1Params = Secp256k1Params {
38    g_x: [
39        0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B,
40        0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8,
41        0x17, 0x98,
42    ],
43    g_y: [
44        0x48, 0x3A, 0xDA, 0x77, 0x26, 0xA3, 0xC4, 0x65, 0x5D, 0xA4, 0xFB, 0xFC, 0x0E, 0x11, 0x08,
45        0xA8, 0xFD, 0x17, 0xB4, 0x48, 0xA6, 0x85, 0x54, 0x19, 0x9C, 0x47, 0xD0, 0x8F, 0xFB, 0x10,
46        0xD4, 0xB8,
47    ],
48};
49
50/// Get the standard base point G of the secp256k1 curve
51pub fn base_point_g() -> Point {
52    Point::new_uncompressed(&SECP256K1.g_x, &SECP256K1.g_y)
53        .expect("Standard base point must be valid")
54}
55
56/// Scalar multiplication with the base point: scalar * G
57pub fn scalar_mult_base_g(scalar: &Scalar) -> Result<Point> {
58    let g = base_point_g();
59    g.mul(scalar)
60}
61
62/// Generate a cryptographically secure ECDH keypair
63pub fn generate_keypair<R: CryptoRng + RngCore>(rng: &mut R) -> Result<(Scalar, Point)> {
64    let mut scalar_bytes = Zeroizing::new([0u8; K256_SCALAR_SIZE]);
65    loop {
66        try_fill_bytes_zeroing_on_error(rng, &mut scalar_bytes[..])?;
67        match Scalar::new(*scalar_bytes) {
68            Ok(private_key) => {
69                let public_key = scalar_mult_base_g(&private_key)?;
70                return Ok((private_key, public_key));
71            }
72            Err(_) => continue,
73        }
74    }
75}
76
77/// General scalar multiplication: compute scalar * point
78pub fn scalar_mult(scalar: &Scalar, point: &Point) -> Result<Point> {
79    if point.is_identity() {
80        return Ok(Point::identity());
81    }
82    point.mul(scalar)
83}
84
85/// Key derivation function for ECDH shared secret using HKDF-SHA256
86pub fn kdf_hkdf_sha256_for_ecdh_kem(
87    ikm: &[u8],
88    info: Option<&[u8]>,
89) -> Result<Zeroizing<[u8; K256_KEM_SHARED_SECRET_KDF_OUTPUT_SIZE]>> {
90    let hkdf_instance = <Hkdf<Sha256, 16> as KdfTrait>::new();
91
92    let derived_key_vec =
93        hkdf_instance.derive_key(ikm, None, info, K256_KEM_SHARED_SECRET_KDF_OUTPUT_SIZE)?;
94
95    let mut output_array = Zeroizing::new([0u8; K256_KEM_SHARED_SECRET_KDF_OUTPUT_SIZE]);
96    if derived_key_vec.len() == K256_KEM_SHARED_SECRET_KDF_OUTPUT_SIZE {
97        output_array.copy_from_slice(&derived_key_vec);
98        Ok(output_array)
99    } else {
100        Err(Error::Length {
101            context: "KDF output for ECDH K256",
102            expected: K256_KEM_SHARED_SECRET_KDF_OUTPUT_SIZE,
103            actual: derived_key_vec.len(),
104        })
105    }
106}
107
108#[cfg(test)]
109mod tests;