1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
5#![allow(clippy::needless_doctest_main)]
6#![doc = include_str!("../README.md")]
7#![warn(missing_docs)]
8
9use std::fmt::Debug;
10
11use aead::{Aead, AeadCore, KeyInit, Nonce};
12use hybrid_array::{Array, ArraySize};
13use rand_core::CryptoRng;
14use sha3::{Digest, Sha3_256};
15use typenum::{U32, Unsigned};
16
17mod curves;
18pub use curves::*;
19
20mod blinding;
21pub use blinding::*;
22
23mod hint;
24pub use hint::*;
25
26mod hints;
27pub use hints::*;
28
29mod take_the;
30pub use take_the::*;
31
32mod error;
33pub use error::*;
34
35pub trait RandomSecretKey {
37 fn random_secret_key(csprng: &mut impl CryptoRng) -> Self;
39}
40
41pub trait Decoy {
43 fn random_decoy(csprng: &mut impl CryptoRng) -> Self;
52}
53
54pub trait KeyPair {
58 type SecretKey: RandomSecretKey;
60 type PublicKey: Debug + Clone + Decoy;
62 type PublicKeySize: ArraySize;
64}
65
66pub(crate) fn cipher_from_shared_secret<A: Aead + KeyInit>(shared_secret: &[u8]) -> Result<A> {
68 Array::try_from_iter(shared_secret.iter().take(A::KeySize::USIZE).copied())
69 .map(|zz| A::new(&zz))
70 .map_err(|_| Error::Aead(aead::Error))
71}
72
73pub(crate) fn shared_secret(
74 raw_shared_secret: &[u8],
75 blinded_blinding_factor: &[u8],
76 context: &[u8],
77) -> Array<u8, U32> {
78 let mut hasher = <Sha3_256 as Digest>::new();
79 hasher.update(raw_shared_secret);
80 hasher.update(blinded_blinding_factor);
81 hasher.update(context);
82
83 hasher.finalize()
84}
85
86pub(crate) fn nonce<A: AeadCore>(blinded_blinding_factor: &[u8]) -> Result<Nonce<A>> {
87 let mut hasher = <Sha3_256 as Digest>::new();
88 hasher.update("ecdh-omr-nonce-");
89 hasher.update(blinded_blinding_factor);
90 let nonce_bytes = hasher.finalize();
91
92 Array::try_from_iter(nonce_bytes.into_iter().take(A::NonceSize::USIZE))
93 .map_err(|_| Error::Aead(aead::Error))
94}