umbral_pre/
hashing_ds.rs

1//! This module contains hashing sequences with included domain separation tags
2//! shared between different parts of the code.
3
4use alloc::boxed::Box;
5use alloc::vec::Vec;
6
7use crate::curve::{CurvePoint, NonZeroCurveScalar};
8use crate::hashing::ScalarDigest;
9use crate::key_frag::KeyFragID;
10use crate::keys::PublicKey;
11
12// These imports are only used in docstrings.
13#[cfg(docsrs)]
14use crate::{Capsule, CapsuleFrag, Parameters, ReencryptionEvidence};
15
16pub(crate) fn hash_to_polynomial_arg(
17    precursor: &CurvePoint,
18    pubkey: &CurvePoint,
19    dh_point: &CurvePoint,
20    kfrag_id: &KeyFragID,
21) -> NonZeroCurveScalar {
22    ScalarDigest::new_with_dst(b"POLYNOMIAL_ARG")
23        .chain_point(precursor)
24        .chain_point(pubkey)
25        .chain_point(dh_point)
26        .chain_bytes(kfrag_id)
27        .finalize()
28}
29
30pub(crate) fn hash_to_shared_secret(
31    precursor: &CurvePoint,
32    pubkey: &CurvePoint,
33    dh_point: &CurvePoint,
34) -> NonZeroCurveScalar {
35    ScalarDigest::new_with_dst(b"SHARED_SECRET")
36        .chain_point(precursor)
37        .chain_point(pubkey)
38        .chain_point(dh_point)
39        .finalize()
40}
41
42pub(crate) fn hash_capsule_points(
43    capsule_e: &CurvePoint,
44    capsule_v: &CurvePoint,
45) -> NonZeroCurveScalar {
46    ScalarDigest::new_with_dst(b"CAPSULE_POINTS")
47        .chain_point(capsule_e)
48        .chain_point(capsule_v)
49        .finalize()
50}
51
52/// Calculates the challenge scalar for the proof of reencryption.
53///
54/// Note: this function is only public for documenting purposes
55/// (see [`ReencryptionEvidence`]).
56///
57/// Calculated as the SHA256 hash of the concatenation of
58/// (the points are represented in the compressed form, 33 bytes each):
59/// - `0x00000012` (4 bytes, the length of the DST)
60/// - `b"CFRAG_VERIFICATION"` (18 bytes)
61/// - `Capsule::e`
62/// - `CapsuleFrag::e1`
63/// - `CapsuleFrag::e2`
64/// - `Capsule::v`
65/// - `CapsuleFrag::v1`
66/// - `CapsuleFrag::v2`
67/// - [`Parameters::u`]
68/// - `CapsuleFrag::u1`
69/// - `CapsuleFrag::u2`
70///
71/// The hash (32 bytes) is then treated as the big-endian representation of an integer,
72/// and converted to a non-zero curve scalar by taking the modulo of `p - 1` and adding 1,
73/// where `p` is the secp256k1 order.
74///
75/// The points mentioned above are the same as in the return values of
76/// [`Capsule::to_bytes_simple`] and [`CapsuleFrag::to_bytes_simple`].
77#[allow(clippy::too_many_arguments)]
78pub fn hash_to_cfrag_verification(
79    e: &CurvePoint,
80    e1: &CurvePoint,
81    e2: &CurvePoint,
82    v: &CurvePoint,
83    v1: &CurvePoint,
84    v2: &CurvePoint,
85    u: &CurvePoint,
86    u1: &CurvePoint,
87    u2: &CurvePoint,
88) -> NonZeroCurveScalar {
89    ScalarDigest::new_with_dst(b"CFRAG_VERIFICATION")
90        .chain_point(e)
91        .chain_point(e1)
92        .chain_point(e2)
93        .chain_point(v)
94        .chain_point(v1)
95        .chain_point(v2)
96        .chain_point(u)
97        .chain_point(u1)
98        .chain_point(u2)
99        .finalize()
100}
101
102fn bool_to_array(val: bool) -> [u8; 1] {
103    if val {
104        [1u8]
105    } else {
106        [0u8]
107    }
108}
109
110pub(crate) fn kfrag_signature_message(
111    kfrag_id: &KeyFragID,
112    commitment: &CurvePoint,
113    precursor: &CurvePoint,
114    maybe_delegating_pk: Option<&PublicKey>,
115    maybe_receiving_pk: Option<&PublicKey>,
116) -> Box<[u8]> {
117    let mut result = Vec::<u8>::new();
118
119    result.extend_from_slice(kfrag_id.as_ref());
120    result.extend_from_slice(&commitment.to_compressed_array());
121    result.extend_from_slice(&precursor.to_compressed_array());
122
123    match maybe_delegating_pk {
124        Some(delegating_pk) => {
125            result.extend_from_slice(&bool_to_array(true));
126            result.extend_from_slice(&delegating_pk.to_point().to_compressed_array())
127        }
128        None => result.extend_from_slice(&bool_to_array(false)),
129    };
130
131    match maybe_receiving_pk {
132        Some(receiving_pk) => {
133            result.extend_from_slice(&bool_to_array(true));
134            result.extend_from_slice(&receiving_pk.to_point().to_compressed_array())
135        }
136        None => result.extend_from_slice(&bool_to_array(false)),
137    };
138
139    result.into_boxed_slice()
140}