dcrypt_algorithms/ec/bls12_381/mod.rs
1//! BLS12-381 pairing-friendly elliptic curve implementation.
2//!
3//! This module exposes low-level group, scalar, RFC 9380 hash-to-curve, and
4//! pairing primitives. It does not implement a complete BLS signature
5//! ciphersuite (including key generation, proof of possession, aggregation,
6//! or protocol-specific input validation).
7//!
8//! The following demonstrates the core equation used by an Eth2-style
9//! minimum-public-key-size construction. Production code must derive a
10//! nonzero secret scalar with the selected ciphersuite's key-generation
11//! procedure, keep its encoded form in zeroizing storage, and enforce that
12//! ciphersuite's validation rules. `Bls12_381Scalar` is a generic `Copy` field
13//! element for public arithmetic, not a protected secret-key container. The
14//! low-level `msm_vartime` helpers likewise accept public scalars only. Secret
15//! scalar multiplication must use `multiply_secret_be_bytes`, or callers should
16//! use the high-level BLS types in `dcrypt-sign`.
17//! External public keys should be decoded with
18//! `G1Projective::from_bytes_validated`, which rejects the identity. Complete
19//! BLS ciphersuites have more nuanced signature identity rules, so callers
20//! should use the high-level types in `dcrypt-sign` rather than assembling a
21//! signature protocol from these primitives.
22//!
23//! ```
24//! use dcrypt_algorithms::ec::bls12_381::{
25//! pairing, G1Affine, G1Projective, G2Affine, G2Projective,
26//! };
27//! use dcrypt_api::types::SecretBytes;
28//!
29//! // Demonstration only: KeyGen normally derives 48 pseudorandom OKM bytes
30//! // using HKDF and reduces it modulo r. SecretBytes owns and clears the
31//! // resulting canonical big-endian scalar.
32//! let mut encoded_secret = [0u8; 32];
33//! encoded_secret[31] = 42;
34//! let secret_bytes = SecretBytes::new(encoded_secret);
35//!
36//! let public_key = G1Affine::from(
37//! G1Projective::generator().multiply_secret_be_bytes(&secret_bytes)?,
38//! );
39//! let message_point = G2Projective::hash_to_curve(
40//! b"message",
41//! b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_",
42//! )?;
43//! let signature = G2Affine::from(message_point.multiply_secret_be_bytes(&secret_bytes)?);
44//! let message_point = G2Affine::from(message_point);
45//!
46//! assert_eq!(
47//! pairing(&public_key, &message_point),
48//! pairing(&G1Affine::generator(), &signature),
49//! );
50//! drop(secret_bytes);
51//! # Ok::<(), dcrypt_algorithms::Error>(())
52//! ```
53
54// External crates
55#[cfg(feature = "alloc")]
56extern crate alloc;
57
58// Module declarations
59mod field;
60mod g1;
61mod g2;
62mod hash_to_curve;
63mod hash_to_curve_g1;
64mod hash_to_curve_g2;
65mod pairings;
66mod scalar;
67
68#[cfg(test)]
69mod tests;
70
71// Internal use for submodules
72use crate::error::Result;
73use scalar::Scalar;
74
75// Public API exports (following dcrypt conventions)
76pub use self::scalar::Scalar as Bls12_381Scalar;
77pub use g1::{G1Affine, G1Projective};
78pub use g2::{G2Affine, G2Projective};
79pub use hash_to_curve::{hash_to_curve_g1, hash_to_curve_g2};
80pub use pairings::{pairing, Bls12, Gt, MillerLoopResult};
81
82#[cfg(feature = "alloc")]
83pub use pairings::{multi_miller_loop, G2Prepared};
84
85// BLS curve parameters
86/// BLS parameter x = -0xd201000000010000
87const BLS_X: u64 = 0xd201_0000_0001_0000;
88/// Sign of BLS parameter x
89const BLS_X_IS_NEGATIVE: bool = true;
90
91impl G1Projective {
92 /// Hash a message to a point on G1 using the hash-to-curve protocol.
93 pub fn hash_to_curve(msg: &[u8], dst: &[u8]) -> Result<Self> {
94 hash_to_curve_g1(msg, dst)
95 }
96}
97
98impl G2Projective {
99 /// Hash a message to a point on G2 using the hash-to-curve protocol.
100 pub fn hash_to_curve(msg: &[u8], dst: &[u8]) -> Result<Self> {
101 hash_to_curve_g2(msg, dst)
102 }
103}