hopr_crypto_packet/
lib.rs1pub mod sphinx;
20
21pub mod errors;
23mod packet;
25mod por;
27mod types;
29mod validation;
31
32#[doc(hidden)]
33pub mod prelude {
34 pub use hopr_types::internal::routing::{HoprSenderId, HoprSurbId};
35
36 pub use super::*;
37 pub use crate::{
38 packet::{
39 HoprForwardedPacket, HoprIncomingPacket, HoprOutgoingPacket, HoprPacket, PacketRouting, PartialHoprPacket,
40 },
41 types::{
42 HOPR_PIX_COMMITMENT_PROOF_SIZE, HoprPixCommitmentProof, HoprPixGroupElement, PacketSignal, PacketSignals,
43 },
44 validation::validate_unacknowledged_ticket,
45 };
46}
47
48use hopr_protocol_pix::{PixGroup, PixScalar};
49use hopr_types::{crypto::prelude::*, internal::prelude::*, primitive::prelude::*};
50use sphinx::prelude::*;
51pub use sphinx::prelude::{ProtocolKeyIdMapper, ReplyOpener};
52
53pub type HoprSphinxSuite = Ed25519Suite;
57
58#[derive(Clone, Copy, Debug, PartialEq, Eq)]
60#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
61pub struct HoprSphinxHeaderSpec;
62
63impl SphinxHeaderSpec for HoprSphinxHeaderSpec {
64 type KeyId = HoprKeyIdent;
65 type PRG = ChaCha20;
66 type PacketReceiverData = HoprSenderId;
67 type Pseudonym = HoprPseudonym;
68 type RelayerData = por::ProofOfRelayString;
69 type SurbReceiverData = types::SurbReceiverInfo;
70 type UH = Poly1305;
71
72 const MAX_HOPS: std::num::NonZeroUsize = std::num::NonZeroUsize::new(INTERMEDIATE_HOPS + 1).unwrap();
73}
74
75pub type HoprKeyIdent = KeyIdent<4>;
77
78pub type HoprSurb = SURB<HoprSphinxSuite, HoprSphinxHeaderSpec>;
80
81pub type HoprReplyOpener = (HoprSurbId, ReplyOpener);
83
84pub(crate) const PAYLOAD_SIZE_INT: usize = DefaultSphinxPacketSize::USIZE - 1; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd, Default)]
95#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
96pub struct HoprPixSpec;
97
98#[cfg(any(feature = "pix-secp256k1", not(feature = "pix-bjj")))]
99impl hopr_protocol_pix::PixSpec for HoprPixSpec {
100 type AddressPrivateKey = ChainKeypair;
101 type Cipher = ChaCha20;
102 type Curve = Secp256k1;
103 type DepositAddress = Address;
104 type Digest = Blake3;
105 type Pseudonym = SimplePseudonym;
106
107 const HASH_TO_SCALAR_SUITE_ID: &'static [u8] = b"Secp256k1_XMD:BLAKE3_SSWU_RO_";
108 const PIX_SUITE: hopr_protocol_pix::PixSuite = hopr_protocol_pix::PixSuite::Secp256k1;
109
110 fn group_to_deposit_address(group: PixGroup<Self>) -> Option<Self::DepositAddress> {
111 PublicKey::try_from(group.to_affine()).ok().map(|pk| pk.to_address())
112 }
113
114 fn scalar_to_private_key(scalar: PixScalar<Self>) -> Option<Self::AddressPrivateKey> {
115 ChainKeypair::from_secret(scalar.to_bytes().as_ref()).ok()
116 }
117}
118
119#[cfg(all(feature = "pix-bjj", not(feature = "pix-secp256k1")))]
120impl hopr_protocol_pix::PixSpec for HoprPixSpec {
121 type AddressPrivateKey = BjjKeypair;
122 type Cipher = ChaCha20;
123 type Curve = BabyJubJub;
124 type DepositAddress = BjjPublicKey;
125 type Digest = Blake3;
126 type Pseudonym = SimplePseudonym;
127
128 const HASH_TO_SCALAR_SUITE_ID: &'static [u8] = b"BabyJubJub_XMD:BLAKE3_SSWU_RO_";
129 const PIX_SUITE: hopr_protocol_pix::PixSuite = hopr_protocol_pix::PixSuite::BabyJubJub;
130
131 fn group_to_deposit_address(group: PixGroup<Self>) -> Option<Self::DepositAddress> {
132 BjjPublicKey::try_from(group).ok()
133 }
134
135 fn scalar_to_private_key(scalar: PixScalar<Self>) -> Option<Self::AddressPrivateKey> {
136 BjjKeypair::from_secret(scalar.to_bytes().as_ref()).ok()
137 }
138}
139
140pub type HoprEncryptedPartialSsaShare = hopr_protocol_pix::EncryptedPartialSsaShare<HoprPixSpec>;
142
143#[cfg(any(feature = "pix-secp256k1", not(feature = "pix-bjj")))]
145pub type HoprShareResolution = hopr_protocol_pix::ShareResolution<SimplePseudonym, ChainKeypair>;
146#[cfg(all(feature = "pix-bjj", not(feature = "pix-secp256k1")))]
147pub type HoprShareResolution = hopr_protocol_pix::ShareResolution<SimplePseudonym, BjjKeypair>;
148
149#[cfg(any(feature = "pix-secp256k1", not(feature = "pix-bjj")))]
151pub type HoprSsaCommitmentState = hopr_protocol_pix::SsaCommitmentState<SimplePseudonym, Address>;
152#[cfg(all(feature = "pix-bjj", not(feature = "pix-secp256k1")))]
153pub type HoprSsaCommitmentState = hopr_protocol_pix::SsaCommitmentState<SimplePseudonym, BjjPublicKey>;
154
155#[cfg(any(feature = "pix-secp256k1", not(feature = "pix-bjj")))]
165pub type HoprPixScalar = crypto_traits::elliptic_curve::Scalar<Secp256k1>;
166#[cfg(all(feature = "pix-bjj", not(feature = "pix-secp256k1")))]
167pub type HoprPixScalar = BabyJubJubScalar;
168
169#[cfg(any(feature = "pix-secp256k1", not(feature = "pix-bjj")))]
180pub type HoprPixGroupRepr = crypto_traits::elliptic_curve::array::Array<u8, crypto_traits::elliptic_curve::consts::U33>;
181#[cfg(all(feature = "pix-bjj", not(feature = "pix-secp256k1")))]
182pub type HoprPixGroupRepr = BabyJubJubCompressedPoint;
183
184#[cfg(test)]
185mod tests {
186 use sphinx::prelude::MetaPacket;
187
188 use super::*;
189 use crate::packet::HoprPacket;
190
191 #[test]
192 fn header_and_packet_lengths() {
193 let hopr_packet_len = HoprPacket::SIZE;
194 assert_eq!(
195 MetaPacket::<HoprSphinxSuite, HoprSphinxHeaderSpec, PAYLOAD_SIZE_INT>::PACKET_LEN + Ticket::SIZE,
196 hopr_packet_len
197 );
198
199 assert!(
200 hopr_packet_len <= 1492 - 31,
201 "HOPR packet of {hopr_packet_len} bytes must fit within a layer 4 packet with libp2p overhead"
202 );
203 }
204
205 #[test]
206 fn packet_length() {
207 let packet_len = HoprPacket::SIZE;
208 assert_eq!(packet_len, 422 + PAYLOAD_SIZE_INT);
209 }
210
211 #[test]
212 fn header_length() {
213 let header_len = HoprSphinxHeaderSpec::HEADER_LEN;
214 assert_eq!(header_len, 241);
215 }
216
217 #[test]
218 fn surb_length() {
219 let surb_len = HoprSurb::SIZE;
220 assert_eq!(surb_len, 402);
222 assert!(HoprPacket::PAYLOAD_SIZE > surb_len * 2);
223 }
224
225 #[test]
226 fn max_surbs_per_packet_must_be_at_least_2() {
227 const _: () = {
228 assert!(HoprPacket::MAX_SURBS_IN_PACKET >= 2);
229 };
230 }
231}