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
//! Hash to curve primitive according to [draft-irtf-cfrg-hash-to-curve](https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/)
//!
//! Some curves have hash to curve primitive implemented. For those curves, `Point<E>` and `Scalar<E>` implement
//! [`FromHash` trait](FromHash).
//!
//! ## Example
//! ```rust
//! use generic_ec::{Point, Scalar, curves::Secp256k1};
//! use generic_ec::hash_to_curve::{FromHash, Tag};
//!
//! // Domain separation tag. Should be unique per application.
//! const TAG: Tag = Tag::new_unwrap(b"MYAPP-v0.1.0");
//!
//! let point = Point::<Secp256k1>::hash(TAG, b"data to be hashed")?;
//! let scalar = Scalar::<Secp256k1>::hash(TAG, b"other data to be hashed")?;
//!
//! # Ok::<_, generic_ec::errors::HashError>(())
//! ```

use crate::as_raw::{FromRaw, TryFromRaw};
use crate::core::hash_to_curve::HashToCurve;
use crate::core::Curve;
use crate::errors::{HashError, HashErrorReason};
use crate::{Point, Scalar};

#[doc(inline)]
pub use crate::core::hash_to_curve::Tag;

/// Hash to curve primitive
pub trait FromHash
where
    Self: Sized,
{
    /// Computes `H(message)`
    #[inline]
    fn hash(tag: Tag, message: &[u8]) -> Result<Self, HashError> {
        Self::hash_concat(tag, &[message])
    }
    /// Computes `H(message[0] || ... || message[len - 1])`
    fn hash_concat(tag: Tag, message: &[&[u8]]) -> Result<Self, HashError>;
}

impl<E> FromHash for Point<E>
where
    E: Curve + HashToCurve,
{
    #[inline]
    fn hash_concat(tag: Tag, message: &[&[u8]]) -> Result<Self, HashError> {
        let point =
            E::hash_to_curve(tag, message).or(Err(HashError(HashErrorReason::HashFailed)))?;
        Point::try_from_raw(point).ok_or(HashError(HashErrorReason::ProducedValueInvalid))
    }
}

impl<E> FromHash for Scalar<E>
where
    E: Curve + HashToCurve,
{
    #[inline]
    fn hash_concat(tag: Tag, message: &[&[u8]]) -> Result<Self, HashError> {
        let scalar =
            E::hash_to_scalar(tag, message).or(Err(HashError(HashErrorReason::HashFailed)))?;
        Ok(Scalar::from_raw(scalar))
    }
}