dalek_ff_group/
ciphersuite.rs

1use zeroize::Zeroize;
2
3use sha2::{Digest, Sha512};
4
5use ciphersuite::{group::Group, Ciphersuite};
6
7use crate::Scalar;
8
9macro_rules! dalek_curve {
10  (
11    $Ciphersuite: ident,
12    $Point:       ident,
13    $ID:          literal
14  ) => {
15    use crate::$Point;
16
17    impl Ciphersuite for $Ciphersuite {
18      type F = Scalar;
19      type G = $Point;
20      type H = Sha512;
21
22      const ID: &'static [u8] = $ID;
23
24      fn generator() -> Self::G {
25        $Point::generator()
26      }
27
28      fn hash_to_F(dst: &[u8], data: &[u8]) -> Self::F {
29        Scalar::from_hash(Sha512::new_with_prefix(&[dst, data].concat()))
30      }
31    }
32  };
33}
34
35/// Ciphersuite for Ristretto.
36///
37/// hash_to_F is implemented with a naive concatenation of the dst and data, allowing transposition
38/// between the two. This means `dst: b"abc", data: b"def"`, will produce the same scalar as
39/// `dst: "abcdef", data: b""`. Please use carefully, not letting dsts be substrings of each other.
40#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
41pub struct Ristretto;
42dalek_curve!(Ristretto, RistrettoPoint, b"ristretto");
43#[test]
44fn test_ristretto() {
45  ff_group_tests::group::test_prime_group_bits::<_, RistrettoPoint>(&mut rand_core::OsRng);
46
47  assert_eq!(
48    Ristretto::hash_to_F(
49      b"FROST-RISTRETTO255-SHA512-v11nonce",
50      &hex::decode(
51        "\
5281800157bb554f299fe0b6bd658e4c4591d74168b5177bf55e8dceed59dc80c7\
535c3430d391552f6e60ecdc093ff9f6f4488756aa6cebdbad75a768010b8f830e"
54      )
55      .unwrap()
56    )
57    .to_bytes()
58    .as_ref(),
59    &hex::decode("40f58e8df202b21c94f826e76e4647efdb0ea3ca7ae7e3689bc0cbe2e2f6660c").unwrap()
60  );
61}
62
63/// Ciphersuite for Ed25519, inspired by RFC-8032.
64///
65/// hash_to_F is implemented with a naive concatenation of the dst and data, allowing transposition
66/// between the two. This means `dst: b"abc", data: b"def"`, will produce the same scalar as
67/// `dst: "abcdef", data: b""`. Please use carefully, not letting dsts be substrings of each other.
68#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
69pub struct Ed25519;
70dalek_curve!(Ed25519, EdwardsPoint, b"edwards25519");
71#[test]
72fn test_ed25519() {
73  ff_group_tests::group::test_prime_group_bits::<_, EdwardsPoint>(&mut rand_core::OsRng);
74
75  // Ideally, a test vector from RFC-8032 (not FROST) would be here
76  // Unfortunately, the IETF draft doesn't provide any vectors for the derived challenges
77  assert_eq!(
78    Ed25519::hash_to_F(
79      b"FROST-ED25519-SHA512-v11nonce",
80      &hex::decode(
81        "\
829d06a6381c7a4493929761a73692776772b274236fb5cfcc7d1b48ac3a9c249f\
83929dcc590407aae7d388761cddb0c0db6f5627aea8e217f4a033f2ec83d93509"
84      )
85      .unwrap()
86    )
87    .to_bytes()
88    .as_ref(),
89    &hex::decode("70652da3e8d7533a0e4b9e9104f01b48c396b5b553717784ed8d05c6a36b9609").unwrap()
90  );
91}