1use std::{
2 fmt::{Debug, Display, Formatter},
3 hash,
4 hash::Hasher,
5 ops::Add,
6 result,
7 str::FromStr,
8 sync::OnceLock,
9};
10
11use cipher::crypto_common::{Output, OutputSizeUser};
12use curve25519_dalek::{
13 edwards::{CompressedEdwardsY, EdwardsPoint},
14 montgomery::MontgomeryPoint,
15};
16use digest::Digest;
17use elliptic_curve::{NonZeroScalar, ProjectivePoint, sec1::EncodedPoint};
18use hopr_crypto_random::Randomizable;
19use hopr_primitive_types::{errors::GeneralError::ParseError, prelude::*};
20use k256::{
21 AffinePoint, Secp256k1,
22 ecdsa::{
23 self, RecoveryId, Signature as ECDSASignature, SigningKey, VerifyingKey,
24 signature::{Verifier, hazmat::PrehashVerifier},
25 },
26 elliptic_curve::{
27 self, CurveArithmetic,
28 generic_array::GenericArray,
29 group::prime::PrimeCurveAffine,
30 sec1::{FromEncodedPoint, ToEncodedPoint},
31 },
32};
33use libp2p_identity::PeerId;
34use sha2::Sha512;
35use sha3::Keccak256;
36use tracing::warn;
37use typenum::Unsigned;
38
39use crate::{
40 errors::{
41 CryptoError::{self, CalculationError, InvalidInputValue},
42 Result,
43 },
44 keypairs::{ChainKeypair, Keypair, OffchainKeypair},
45 utils::random_group_element,
46};
47
48#[derive(Clone, Debug)]
76pub struct CurvePoint {
77 pub(crate) affine: AffinePoint,
78 compressed: EncodedPoint<Secp256k1>,
79 uncompressed: OnceLock<EncodedPoint<Secp256k1>>,
80}
81
82impl CurvePoint {
83 pub const SIZE_COMPRESSED: usize = 33;
85 pub const SIZE_UNCOMPRESSED: usize = 65;
87
88 pub fn to_address(&self) -> Address {
90 let serialized = self.as_uncompressed();
91 let hash = Hash::create(&[&serialized.as_bytes()[1..]]);
92 Address::new(&hash.as_ref()[12..])
93 }
94
95 pub fn from_exponent(exponent: &[u8]) -> Result<Self> {
99 PublicKey::from_privkey(exponent).map(CurvePoint::from)
100 }
101
102 pub fn into_projective_point(self) -> ProjectivePoint<Secp256k1> {
104 self.affine.into()
105 }
106
107 pub fn as_compressed(&self) -> &EncodedPoint<Secp256k1> {
109 &self.compressed
110 }
111
112 pub fn as_uncompressed(&self) -> &EncodedPoint<Secp256k1> {
114 self.uncompressed.get_or_init(|| self.affine.to_encoded_point(false))
115 }
116
117 pub fn combine(summands: &[&CurvePoint]) -> CurvePoint {
119 let affine: AffinePoint = summands
122 .iter()
123 .map(|p| ProjectivePoint::<Secp256k1>::from(p.affine))
124 .fold(<Secp256k1 as CurveArithmetic>::ProjectivePoint::IDENTITY, |acc, x| {
125 acc.add(x)
126 })
127 .to_affine();
128
129 affine.into()
130 }
131}
132
133impl std::hash::Hash for CurvePoint {
134 fn hash<H: Hasher>(&self, state: &mut H) {
135 self.compressed.hash(state);
136 }
137}
138
139impl Default for CurvePoint {
140 fn default() -> Self {
141 Self::from(AffinePoint::default())
142 }
143}
144
145impl PartialEq for CurvePoint {
146 fn eq(&self, other: &Self) -> bool {
147 self.affine.eq(&other.affine)
148 }
149}
150
151impl Eq for CurvePoint {}
152
153impl From<PublicKey> for CurvePoint {
154 fn from(pubkey: PublicKey) -> Self {
155 pubkey.0
156 }
157}
158
159impl From<&PublicKey> for CurvePoint {
160 fn from(pubkey: &PublicKey) -> Self {
161 pubkey.0.clone()
162 }
163}
164
165impl From<AffinePoint> for CurvePoint {
166 fn from(affine: AffinePoint) -> Self {
167 Self {
168 affine,
169 compressed: affine.to_encoded_point(true),
170 uncompressed: OnceLock::new(),
171 }
172 }
173}
174
175impl TryFrom<HalfKeyChallenge> for CurvePoint {
176 type Error = GeneralError;
177
178 fn try_from(value: HalfKeyChallenge) -> std::result::Result<Self, Self::Error> {
179 Self::try_from(value.0.as_ref())
180 }
181}
182
183impl FromStr for CurvePoint {
184 type Err = CryptoError;
185
186 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
187 Ok(CurvePoint::try_from(
188 hex::decode(s)
189 .map_err(|_| GeneralError::ParseError("CurvePoint".into()))?
190 .as_slice(),
191 )?)
192 }
193}
194
195impl From<CurvePoint> for AffinePoint {
196 fn from(value: CurvePoint) -> Self {
197 value.affine
198 }
199}
200
201impl AsRef<[u8]> for CurvePoint {
202 fn as_ref(&self) -> &[u8] {
203 self.compressed.as_ref()
204 }
205}
206
207impl TryFrom<&[u8]> for CurvePoint {
208 type Error = GeneralError;
209
210 fn try_from(value: &[u8]) -> std::result::Result<Self, Self::Error> {
211 let ep = elliptic_curve::sec1::EncodedPoint::<Secp256k1>::from_bytes(value)
212 .map_err(|_| GeneralError::ParseError("invalid secp256k1 encoded point".into()))?;
213 Ok(Self {
214 affine: Option::from(AffinePoint::from_encoded_point(&ep))
215 .ok_or(GeneralError::ParseError("invalid secp256k1 encoded point".into()))?,
216 compressed: if ep.is_compressed() { ep } else { ep.compress() },
218 uncompressed: if !ep.is_compressed() {
220 ep.into()
221 } else {
222 OnceLock::new()
223 },
224 })
225 }
226}
227
228impl BytesRepresentable for CurvePoint {
229 const SIZE: usize = Self::SIZE_COMPRESSED;
230}
231
232#[derive(Clone, Eq, PartialEq, Debug)]
235pub struct Challenge(CurvePoint);
236
237impl Challenge {
238 pub fn to_ethereum_challenge(&self) -> EthereumChallenge {
242 EthereumChallenge::new(self.0.to_address().as_ref())
243 }
244}
245
246impl From<Challenge> for EthereumChallenge {
247 fn from(challenge: Challenge) -> Self {
248 challenge.to_ethereum_challenge()
249 }
250}
251
252impl Challenge {
253 pub fn from_hint_and_share(own_share: &HalfKeyChallenge, hint: &HalfKeyChallenge) -> Result<Self> {
255 let curve_point: CurvePoint = PublicKey::combine(&[
256 &PublicKey::try_from(own_share.0.as_ref())?,
257 &PublicKey::try_from(hint.0.as_ref())?,
258 ])
259 .into();
260 Ok(curve_point.into())
261 }
262
263 pub fn from_own_share_and_half_key(own_share: &HalfKeyChallenge, half_key: &HalfKey) -> Result<Self> {
266 Self::from_hint_and_share(own_share, &half_key.to_challenge())
267 }
268}
269
270impl From<CurvePoint> for Challenge {
271 fn from(curve_point: CurvePoint) -> Self {
272 Self(curve_point)
273 }
274}
275
276impl From<Response> for Challenge {
277 fn from(response: Response) -> Self {
278 response.to_challenge()
279 }
280}
281
282impl AsRef<[u8]> for Challenge {
283 fn as_ref(&self) -> &[u8] {
284 self.0.as_ref()
286 }
287}
288
289impl TryFrom<&[u8]> for Challenge {
290 type Error = GeneralError;
291
292 fn try_from(value: &[u8]) -> std::result::Result<Self, Self::Error> {
293 Ok(Self(value.try_into()?))
295 }
296}
297
298impl BytesRepresentable for Challenge {
299 const SIZE: usize = CurvePoint::SIZE_COMPRESSED;
300}
301
302#[derive(Debug, Copy, Clone, Eq, PartialEq)]
307#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
308pub struct HalfKey(#[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] [u8; Self::SIZE]);
309
310impl Default for HalfKey {
311 fn default() -> Self {
312 let mut ret = Self([0u8; Self::SIZE]);
313
314 ret.0.copy_from_slice(
315 NonZeroScalar::<Secp256k1>::from_uint(1u16.into())
316 .unwrap()
317 .to_bytes()
318 .as_slice(),
319 );
320 ret
321 }
322}
323
324impl HalfKey {
325 pub fn to_challenge(&self) -> HalfKeyChallenge {
328 CurvePoint::from_exponent(&self.0)
329 .map(|cp| HalfKeyChallenge::new(cp.as_compressed().as_bytes()))
330 .expect("invalid public key")
331 }
332}
333
334impl Randomizable for HalfKey {
335 fn random() -> Self {
336 Self(random_group_element().0)
337 }
338}
339
340impl AsRef<[u8]> for HalfKey {
341 fn as_ref(&self) -> &[u8] {
342 &self.0
343 }
344}
345
346impl TryFrom<&[u8]> for HalfKey {
347 type Error = GeneralError;
348
349 fn try_from(value: &[u8]) -> std::result::Result<Self, Self::Error> {
350 Ok(Self(value.try_into().map_err(|_| ParseError("HalfKey".into()))?))
351 }
352}
353
354impl BytesRepresentable for HalfKey {
355 const SIZE: usize = 32;
357}
358
359#[derive(Debug, Clone, Copy, Eq, PartialEq)]
363#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
364pub struct HalfKeyChallenge(#[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] [u8; Self::SIZE]);
365
366impl Display for HalfKeyChallenge {
367 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
368 write!(f, "{}", hex::encode(self.0))
369 }
370}
371
372impl Default for HalfKeyChallenge {
373 fn default() -> Self {
374 let mut ret = Self([0u8; Self::SIZE]);
377 ret.0[Self::SIZE - 1] = 1;
378 ret
379 }
380}
381
382impl HalfKeyChallenge {
383 pub fn new(half_key_challenge: &[u8]) -> Self {
384 let mut ret = Self::default();
385 ret.0.copy_from_slice(half_key_challenge);
386 ret
387 }
388
389 pub fn to_address(&self) -> Address {
390 PublicKey::try_from(self.0.as_ref())
391 .expect("invalid half-key")
392 .to_address()
393 }
394}
395
396impl AsRef<[u8]> for HalfKeyChallenge {
397 fn as_ref(&self) -> &[u8] {
398 &self.0
399 }
400}
401
402impl TryFrom<&[u8]> for HalfKeyChallenge {
403 type Error = GeneralError;
404
405 fn try_from(value: &[u8]) -> std::result::Result<Self, Self::Error> {
406 Ok(Self(
407 value.try_into().map_err(|_| ParseError("HalfKeyChallenge".into()))?,
408 ))
409 }
410}
411
412impl BytesRepresentable for HalfKeyChallenge {
413 const SIZE: usize = PublicKey::SIZE_COMPRESSED;
415}
416
417impl std::hash::Hash for HalfKeyChallenge {
418 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
419 self.0.hash(state);
420 }
421}
422
423impl FromStr for HalfKeyChallenge {
424 type Err = GeneralError;
425
426 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
427 Self::from_hex(s)
428 }
429}
430
431impl From<HalfKey> for HalfKeyChallenge {
432 fn from(half_key: HalfKey) -> Self {
433 half_key.to_challenge()
434 }
435}
436
437#[derive(Clone, Copy, Eq, PartialEq, Default, PartialOrd, Ord, std::hash::Hash)]
440#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
441pub struct Hash(#[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] [u8; Self::SIZE]);
442
443impl Debug for Hash {
444 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
446 write!(f, "{}", self.to_hex())
447 }
448}
449
450impl Display for Hash {
451 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
452 write!(f, "{}", self.to_hex())
453 }
454}
455
456impl FromStr for Hash {
457 type Err = GeneralError;
458
459 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
460 Self::from_hex(s)
461 }
462}
463
464impl Hash {
465 pub fn hash(&self) -> Self {
467 Self::create(&[&self.0])
468 }
469
470 pub fn create(inputs: &[&[u8]]) -> Self {
473 let mut output = Output::<Keccak256>::default();
474 let mut hash = Keccak256::default();
475 inputs.iter().for_each(|v| hash.update(v));
476 hash.finalize_into(&mut output);
477 Self(output.into())
478 }
479}
480
481impl AsRef<[u8]> for Hash {
482 fn as_ref(&self) -> &[u8] {
483 &self.0
484 }
485}
486
487impl TryFrom<&[u8]> for Hash {
488 type Error = GeneralError;
489
490 fn try_from(value: &[u8]) -> std::result::Result<Self, Self::Error> {
491 Ok(Self(value.try_into().map_err(|_| ParseError("Hash".into()))?))
492 }
493}
494
495impl BytesRepresentable for Hash {
496 const SIZE: usize = <Keccak256 as OutputSizeUser>::OutputSize::USIZE;
498}
499
500impl From<[u8; Self::SIZE]> for Hash {
501 fn from(hash: [u8; Self::SIZE]) -> Self {
502 Self(hash)
503 }
504}
505
506impl From<Hash> for [u8; Hash::SIZE] {
507 fn from(value: Hash) -> Self {
508 value.0
509 }
510}
511
512impl From<&Hash> for [u8; Hash::SIZE] {
513 fn from(value: &Hash) -> Self {
514 value.0
515 }
516}
517
518impl From<Hash> for primitive_types::H256 {
519 fn from(value: Hash) -> Self {
520 value.0.into()
521 }
522}
523
524impl From<primitive_types::H256> for Hash {
525 fn from(value: primitive_types::H256) -> Self {
526 Self(value.0)
527 }
528}
529
530#[derive(Clone, Copy, Eq)]
532#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
533pub struct OffchainPublicKey {
534 compressed: CompressedEdwardsY,
535 edwards: EdwardsPoint,
536 montgomery: MontgomeryPoint,
537}
538
539impl std::fmt::Debug for OffchainPublicKey {
540 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
541 f.debug_struct("OffchainPublicKey")
542 .field("compressed", &self.compressed)
543 .finish()
544 }
545}
546
547impl std::hash::Hash for OffchainPublicKey {
548 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
549 self.compressed.hash(state);
550 }
551}
552
553impl PartialEq for OffchainPublicKey {
554 fn eq(&self, other: &Self) -> bool {
555 self.compressed == other.compressed
556 }
557}
558
559impl AsRef<[u8]> for OffchainPublicKey {
560 fn as_ref(&self) -> &[u8] {
561 self.compressed.as_bytes()
562 }
563}
564
565impl TryFrom<&[u8]> for OffchainPublicKey {
566 type Error = GeneralError;
567
568 fn try_from(value: &[u8]) -> std::result::Result<Self, Self::Error> {
569 let compressed = CompressedEdwardsY::from_slice(value).map_err(|_| ParseError("OffchainPublicKey".into()))?;
570 let edwards = compressed
571 .decompress()
572 .ok_or(ParseError("OffchainPublicKey.decompress".into()))?;
573 Ok(Self {
574 compressed,
575 edwards,
576 montgomery: edwards.to_montgomery(),
577 })
578 }
579}
580
581impl BytesRepresentable for OffchainPublicKey {
582 const SIZE: usize = 32;
584}
585
586impl TryFrom<[u8; OffchainPublicKey::SIZE]> for OffchainPublicKey {
587 type Error = GeneralError;
588
589 fn try_from(value: [u8; OffchainPublicKey::SIZE]) -> std::result::Result<Self, Self::Error> {
590 let v: &[u8] = &value;
591 v.try_into()
592 }
593}
594
595impl TryFrom<&PeerId> for OffchainPublicKey {
596 type Error = GeneralError;
597
598 fn try_from(value: &PeerId) -> std::result::Result<Self, Self::Error> {
599 let mh = value.as_ref();
600 if mh.code() == 0 {
601 libp2p_identity::PublicKey::try_decode_protobuf(mh.digest())
602 .map_err(|_| GeneralError::ParseError("invalid ed25519 peer id".into()))
603 .and_then(|pk| {
604 pk.try_into_ed25519()
605 .map(|p| p.to_bytes())
606 .map_err(|_| GeneralError::ParseError("invalid ed25519 peer id".into()))
607 })
608 .and_then(Self::try_from)
609 } else {
610 Err(GeneralError::ParseError("invalid ed25519 peer id".into()))
611 }
612 }
613}
614
615impl TryFrom<PeerId> for OffchainPublicKey {
616 type Error = GeneralError;
617
618 fn try_from(value: PeerId) -> std::result::Result<Self, Self::Error> {
619 Self::try_from(&value)
620 }
621}
622
623impl From<OffchainPublicKey> for PeerId {
624 fn from(value: OffchainPublicKey) -> Self {
625 let k = libp2p_identity::ed25519::PublicKey::try_from_bytes(value.compressed.as_bytes()).unwrap();
626 PeerId::from_public_key(&k.into())
627 }
628}
629
630impl From<&OffchainPublicKey> for PeerId {
631 fn from(value: &OffchainPublicKey) -> Self {
632 (*value).into()
633 }
634}
635
636impl Display for OffchainPublicKey {
637 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
638 write!(f, "{}", self.to_hex())
639 }
640}
641
642impl OffchainPublicKey {
643 pub fn from_privkey(private_key: &[u8]) -> Result<Self> {
646 let mut pk: [u8; ed25519_dalek::SECRET_KEY_LENGTH] =
647 private_key.try_into().map_err(|_| InvalidInputValue("private_key"))?;
648 let sk = libp2p_identity::ed25519::SecretKey::try_from_bytes(&mut pk)
649 .map_err(|_| InvalidInputValue("private_key"))?;
650 let kp: libp2p_identity::ed25519::Keypair = sk.into();
651 Ok(Self::try_from(kp.public().to_bytes())?)
652 }
653
654 pub fn to_peerid_str(&self) -> String {
656 PeerId::from(self).to_base58()
657 }
658}
659
660impl From<&OffchainPublicKey> for EdwardsPoint {
661 fn from(value: &OffchainPublicKey) -> Self {
662 value.edwards
663 }
664}
665
666impl From<&OffchainPublicKey> for MontgomeryPoint {
667 fn from(value: &OffchainPublicKey) -> Self {
668 value.montgomery
669 }
670}
671
672#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
674#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
675pub struct CompactOffchainPublicKey(CompressedEdwardsY);
676
677impl From<OffchainPublicKey> for CompactOffchainPublicKey {
678 fn from(value: OffchainPublicKey) -> Self {
679 Self(value.compressed)
680 }
681}
682
683impl CompactOffchainPublicKey {
684 pub fn into_offchain_public_key(self) -> OffchainPublicKey {
686 let decompressed = self.0.decompress().expect("decompression must not fail");
687 OffchainPublicKey {
688 compressed: self.0,
689 edwards: decompressed,
690 montgomery: decompressed.to_montgomery(),
691 }
692 }
693}
694
695pub const PACKET_TAG_LENGTH: usize = 16;
697
698pub type PacketTag = [u8; PACKET_TAG_LENGTH];
700
701#[derive(Debug, Clone, Eq, PartialEq, Hash)]
746pub struct PublicKey(CurvePoint);
747
748impl PublicKey {
749 pub const SIZE_COMPRESSED: usize = 33;
751 pub const SIZE_UNCOMPRESSED: usize = 65;
753 pub const SIZE_UNCOMPRESSED_PLAIN: usize = 64;
754
755 pub fn from_privkey(private_key: &[u8]) -> Result<PublicKey> {
756 let secret_scalar = NonZeroScalar::<Secp256k1>::try_from(private_key)
758 .map_err(|_| GeneralError::ParseError("PublicKey".into()))?;
759
760 let key = elliptic_curve::PublicKey::<Secp256k1>::from_secret_scalar(&secret_scalar);
761 Ok(key.into())
762 }
763
764 fn from_raw_signature<R>(msg: &[u8], r: &[u8], s: &[u8], v: u8, recovery_method: R) -> Result<PublicKey>
765 where
766 R: Fn(&[u8], &ECDSASignature, RecoveryId) -> std::result::Result<VerifyingKey, ecdsa::Error>,
767 {
768 let recid = RecoveryId::try_from(v).map_err(|_| GeneralError::ParseError("Signature".into()))?;
769 let signature =
770 ECDSASignature::from_scalars(GenericArray::clone_from_slice(r), GenericArray::clone_from_slice(s))
771 .map_err(|_| GeneralError::ParseError("Signature".into()))?;
772
773 let recovered_key = *recovery_method(msg, &signature, recid)
774 .map_err(|_| CalculationError)?
775 .as_affine();
776
777 recovered_key.try_into()
779 }
780
781 pub fn from_signature(msg: &[u8], signature: &Signature) -> Result<PublicKey> {
782 let (raw_signature, recovery) = signature.raw_signature();
783 Self::from_raw_signature(
784 msg,
785 &raw_signature[0..Signature::SIZE / 2],
786 &raw_signature[Signature::SIZE / 2..],
787 recovery,
788 VerifyingKey::recover_from_msg,
789 )
790 }
791
792 pub fn from_signature_hash(hash: &[u8], signature: &Signature) -> Result<PublicKey> {
793 let (raw_signature, recovery) = signature.raw_signature();
794 Self::from_raw_signature(
795 hash,
796 &raw_signature[0..Signature::SIZE / 2],
797 &raw_signature[Signature::SIZE / 2..],
798 recovery,
799 VerifyingKey::recover_from_prehash,
800 )
801 }
802
803 pub fn combine(summands: &[&PublicKey]) -> PublicKey {
806 let cps = summands.iter().map(|pk| CurvePoint::from(*pk)).collect::<Vec<_>>();
807 let cps_ref = cps.iter().collect::<Vec<_>>();
808
809 CurvePoint::combine(&cps_ref)
811 .try_into()
812 .expect("combination results in the ec identity (which is an invalid pub key)")
813 }
814
815 pub fn tweak_add(key: &PublicKey, tweak: &[u8]) -> PublicKey {
818 let scalar = NonZeroScalar::<Secp256k1>::try_from(tweak).expect("zero tweak provided");
819
820 let new_pk = (key.0.clone().into_projective_point()
821 + <Secp256k1 as CurveArithmetic>::ProjectivePoint::GENERATOR * scalar.as_ref())
822 .to_affine();
823
824 new_pk.try_into().expect("tweak add resulted in an invalid public key")
826 }
827
828 pub fn to_address(&self) -> Address {
830 let uncompressed = self.to_bytes(false);
831 let serialized = Hash::create(&[&uncompressed[1..]]);
832 Address::new(&serialized.as_ref()[12..])
833 }
834
835 pub fn to_bytes(&self, compressed: bool) -> Box<[u8]> {
837 match compressed {
838 true => self.0.as_compressed().to_bytes(),
839 false => self.0.as_uncompressed().to_bytes(),
840 }
841 }
842
843 pub fn to_hex(&self, compressed: bool) -> String {
845 let offset = if compressed { 0 } else { 1 };
846 format!("0x{}", hex::encode(&self.to_bytes(compressed)[offset..]))
847 }
848}
849
850impl Randomizable for PublicKey {
851 fn random() -> Self {
854 let (_, cp) = random_group_element();
855 cp.try_into()
856 .expect("random_group_element cannot generate identity points")
857 }
858}
859
860impl Display for PublicKey {
861 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
862 write!(f, "{}", self.to_hex(true))
863 }
864}
865
866impl TryFrom<&[u8]> for PublicKey {
867 type Error = GeneralError;
868
869 fn try_from(value: &[u8]) -> std::result::Result<Self, Self::Error> {
870 match value.len() {
871 Self::SIZE_UNCOMPRESSED => {
872 let key = elliptic_curve::PublicKey::<Secp256k1>::from_sec1_bytes(value)
874 .map_err(|_| GeneralError::ParseError("invalid secp256k1 point".into()))?;
875
876 Ok(key.into())
878 }
879 Self::SIZE_UNCOMPRESSED_PLAIN => {
880 let key = elliptic_curve::PublicKey::<Secp256k1>::from_sec1_bytes(&[&[4u8], value].concat())
882 .map_err(|_| GeneralError::ParseError("invalid secp256k1 point".into()))?;
883
884 Ok(key.into())
886 }
887 Self::SIZE_COMPRESSED => {
888 let key = elliptic_curve::PublicKey::<Secp256k1>::from_sec1_bytes(value)
890 .map_err(|_| GeneralError::ParseError("invalid secp256k1 point".into()))?;
891
892 Ok(key.into())
894 }
895 _ => Err(GeneralError::ParseError("invalid secp256k1 point".into())),
896 }
897 }
898}
899
900impl TryFrom<AffinePoint> for PublicKey {
901 type Error = CryptoError;
902
903 fn try_from(value: AffinePoint) -> std::result::Result<Self, Self::Error> {
904 if value.is_identity().into() {
905 return Err(CryptoError::InvalidPublicKey);
906 }
907 Ok(Self(value.into()))
908 }
909}
910
911impl TryFrom<CurvePoint> for PublicKey {
912 type Error = CryptoError;
913
914 fn try_from(value: CurvePoint) -> std::result::Result<Self, Self::Error> {
915 if value.affine.is_identity().into() {
916 return Err(CryptoError::InvalidPublicKey);
917 }
918 Ok(Self(value))
919 }
920}
921
922impl From<elliptic_curve::PublicKey<Secp256k1>> for PublicKey {
923 fn from(key: elliptic_curve::PublicKey<Secp256k1>) -> Self {
924 Self((*key.as_affine()).into())
925 }
926}
927
928impl From<&PublicKey> for k256::ProjectivePoint {
930 fn from(value: &PublicKey) -> Self {
931 value.0.clone().into_projective_point()
932 }
933}
934
935#[derive(Debug, PartialEq, Eq, Clone, Hash)]
937pub struct CompressedPublicKey(pub PublicKey);
938
939impl TryFrom<&[u8]> for CompressedPublicKey {
940 type Error = GeneralError;
941
942 fn try_from(value: &[u8]) -> std::result::Result<Self, Self::Error> {
943 Ok(PublicKey::try_from(value)?.into())
944 }
945}
946
947impl AsRef<[u8]> for CompressedPublicKey {
948 fn as_ref(&self) -> &[u8] {
949 self.0.0.as_ref()
951 }
952}
953
954impl BytesRepresentable for CompressedPublicKey {
955 const SIZE: usize = PublicKey::SIZE_COMPRESSED;
956}
957
958impl From<PublicKey> for CompressedPublicKey {
959 fn from(value: PublicKey) -> Self {
960 Self(value)
961 }
962}
963
964impl From<&CompressedPublicKey> for k256::ProjectivePoint {
965 fn from(value: &CompressedPublicKey) -> Self {
966 (&value.0).into()
967 }
968}
969
970impl CompressedPublicKey {
971 pub fn to_address(&self) -> Address {
972 self.0.to_address()
973 }
974}
975
976#[derive(Clone, Debug, PartialEq, Eq)]
979#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
980pub struct Response(#[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] [u8; Self::SIZE]);
981
982impl Default for Response {
983 fn default() -> Self {
984 Self(HalfKey::default().0)
985 }
986}
987
988impl Display for Response {
989 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
990 f.write_str(self.to_hex().as_str())
991 }
992}
993
994impl Response {
995 pub fn to_challenge(&self) -> Challenge {
998 Challenge(CurvePoint::from_exponent(&self.0).expect("response represents an invalid non-zero scalar"))
999 }
1000
1001 pub fn from_half_keys(first: &HalfKey, second: &HalfKey) -> Result<Self> {
1005 let res = NonZeroScalar::<Secp256k1>::try_from(first.as_ref())
1006 .and_then(|s1| NonZeroScalar::<Secp256k1>::try_from(second.as_ref()).map(|s2| s1.as_ref() + s2.as_ref()))
1007 .map_err(|_| CalculationError)?; Ok(Response::try_from(res.to_bytes().as_slice())?)
1010 }
1011}
1012
1013impl AsRef<[u8]> for Response {
1014 fn as_ref(&self) -> &[u8] {
1015 &self.0
1016 }
1017}
1018
1019impl TryFrom<&[u8]> for Response {
1020 type Error = GeneralError;
1021
1022 fn try_from(value: &[u8]) -> std::result::Result<Self, Self::Error> {
1023 Ok(Self(value.try_into().map_err(|_| ParseError("Response".into()))?))
1024 }
1025}
1026
1027impl BytesRepresentable for Response {
1028 const SIZE: usize = 32;
1030}
1031
1032impl From<[u8; Self::SIZE]> for Response {
1033 fn from(value: [u8; Self::SIZE]) -> Self {
1034 Self(value)
1035 }
1036}
1037
1038#[derive(Clone, Debug, PartialEq, Eq)]
1040#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1041pub struct OffchainSignature(#[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] [u8; Self::SIZE]);
1042
1043impl OffchainSignature {
1044 pub fn sign_message(msg: &[u8], signing_keypair: &OffchainKeypair) -> Self {
1046 let expanded_sk = ed25519_dalek::hazmat::ExpandedSecretKey::from(
1048 &ed25519_dalek::SecretKey::try_from(signing_keypair.secret().as_ref()).expect("invalid private key"),
1049 );
1050
1051 let verifying = ed25519_dalek::VerifyingKey::from(signing_keypair.public().edwards);
1054
1055 ed25519_dalek::hazmat::raw_sign::<Sha512>(&expanded_sk, msg, &verifying).into()
1056 }
1057
1058 pub fn verify_message(&self, msg: &[u8], public_key: &OffchainPublicKey) -> bool {
1060 let sgn = ed25519_dalek::Signature::from_slice(&self.0).expect("corrupted OffchainSignature");
1061 let pk = ed25519_dalek::VerifyingKey::from(public_key.edwards);
1062 pk.verify_strict(msg, &sgn).is_ok()
1063 }
1064}
1065
1066impl AsRef<[u8]> for OffchainSignature {
1067 fn as_ref(&self) -> &[u8] {
1068 &self.0
1069 }
1070}
1071
1072impl TryFrom<&[u8]> for OffchainSignature {
1073 type Error = GeneralError;
1074
1075 fn try_from(value: &[u8]) -> std::result::Result<Self, Self::Error> {
1076 Ok(ed25519_dalek::Signature::from_slice(value)
1077 .map_err(|_| ParseError("OffchainSignature".into()))?
1078 .into())
1079 }
1080}
1081
1082impl BytesRepresentable for OffchainSignature {
1083 const SIZE: usize = ed25519_dalek::Signature::BYTE_SIZE;
1085}
1086
1087impl From<ed25519_dalek::Signature> for OffchainSignature {
1088 fn from(value: ed25519_dalek::Signature) -> Self {
1089 let mut ret = Self([0u8; Self::SIZE]);
1090 ret.0.copy_from_slice(value.to_bytes().as_ref());
1091 ret
1092 }
1093}
1094
1095impl TryFrom<([u8; 32], [u8; 32])> for OffchainSignature {
1096 type Error = GeneralError;
1097
1098 fn try_from(value: ([u8; 32], [u8; 32])) -> std::result::Result<Self, Self::Error> {
1099 Ok(ed25519_dalek::Signature::from_components(value.0, value.1).into())
1100 }
1101}
1102
1103#[derive(Clone, Copy, Debug)]
1110#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1111pub struct Signature(#[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] [u8; Self::SIZE]);
1112
1113impl Signature {
1114 pub fn new(raw_bytes: &[u8], recovery: u8) -> Signature {
1115 assert!(recovery <= 1, "invalid recovery bit");
1116
1117 let mut ret = Self([0u8; Self::SIZE]);
1118 ret.0.copy_from_slice(raw_bytes);
1119 ret.embed_recovery_bit(recovery);
1120 ret
1121 }
1122
1123 fn sign<S>(data: &[u8], private_key: &[u8], signing_method: S) -> Signature
1124 where
1125 S: FnOnce(&SigningKey, &[u8]) -> ecdsa::signature::Result<(ECDSASignature, RecoveryId)>,
1126 {
1127 let key = SigningKey::from_bytes(private_key.into()).expect("invalid signing key");
1128 let (sig, rec) = signing_method(&key, data).expect("signing failed");
1129
1130 Self::new(&sig.to_vec(), rec.to_byte())
1131 }
1132
1133 pub fn sign_message(message: &[u8], chain_keypair: &ChainKeypair) -> Signature {
1135 Self::sign(
1136 message,
1137 chain_keypair.secret().as_ref(),
1138 |k: &SigningKey, data: &[u8]| k.sign_recoverable(data),
1139 )
1140 }
1141
1142 pub fn sign_hash(hash: &[u8], chain_keypair: &ChainKeypair) -> Signature {
1144 Self::sign(hash, chain_keypair.secret().as_ref(), |k: &SigningKey, data: &[u8]| {
1145 k.sign_prehash_recoverable(data)
1146 })
1147 }
1148
1149 fn verify<V>(&self, message: &[u8], public_key: &[u8], verifier: V) -> bool
1150 where
1151 V: FnOnce(&VerifyingKey, &[u8], &ECDSASignature) -> ecdsa::signature::Result<()>,
1152 {
1153 let pub_key = VerifyingKey::from_sec1_bytes(public_key).expect("invalid public key");
1154
1155 if let Ok(signature) = ECDSASignature::try_from(self.raw_signature().0.as_ref()) {
1156 verifier(&pub_key, message, &signature).is_ok()
1157 } else {
1158 warn!("un-parseable signature encountered");
1159 false
1160 }
1161 }
1162
1163 pub fn verify_message(&self, message: &[u8], public_key: &PublicKey) -> bool {
1165 self.verify(message, &public_key.to_bytes(false), |k, msg, sgn| k.verify(msg, sgn))
1166 }
1167
1168 pub fn verify_hash(&self, hash: &[u8], public_key: &PublicKey) -> bool {
1170 self.verify(hash, &public_key.to_bytes(false), |k, msg, sgn| {
1171 k.verify_prehash(msg, sgn)
1172 })
1173 }
1174
1175 pub fn raw_signature(&self) -> ([u8; Self::SIZE], u8) {
1178 let mut raw_sig = self.0;
1179 let recovery: u8 = (raw_sig[Self::SIZE / 2] & 0x80 != 0).into();
1180 raw_sig[Self::SIZE / 2] &= 0x7f;
1181 (raw_sig, recovery)
1182 }
1183
1184 fn embed_recovery_bit(&mut self, recovery: u8) {
1185 self.0[Self::SIZE / 2] &= 0x7f;
1186 self.0[Self::SIZE / 2] |= recovery << 7;
1187 }
1188}
1189
1190impl AsRef<[u8]> for Signature {
1191 fn as_ref(&self) -> &[u8] {
1192 &self.0
1193 }
1194}
1195
1196impl TryFrom<&[u8]> for Signature {
1197 type Error = GeneralError;
1198
1199 fn try_from(value: &[u8]) -> std::result::Result<Self, Self::Error> {
1200 Ok(Self(value.try_into().map_err(|_| ParseError("Signature".into()))?))
1201 }
1202}
1203
1204impl BytesRepresentable for Signature {
1205 const SIZE: usize = 64;
1206}
1207
1208impl PartialEq for Signature {
1209 fn eq(&self, other: &Self) -> bool {
1210 self.0.eq(&other.0)
1211 }
1212}
1213
1214impl Eq for Signature {}
1215
1216pub trait Pseudonym: BytesRepresentable + hash::Hash + Eq + Display + Randomizable {}
1222
1223#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1225#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1226pub struct SimplePseudonym(#[cfg_attr(feature = "serde", serde(with = "serde_bytes"))] pub [u8; Self::SIZE]);
1227
1228impl Display for SimplePseudonym {
1229 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1230 write!(f, "{}", self.to_hex())
1231 }
1232}
1233
1234impl Debug for SimplePseudonym {
1235 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1236 write!(f, "{}", self.to_hex())
1237 }
1238}
1239
1240impl BytesRepresentable for SimplePseudonym {
1241 const SIZE: usize = 10;
1242}
1243
1244impl AsRef<[u8]> for SimplePseudonym {
1245 fn as_ref(&self) -> &[u8] {
1246 &self.0
1247 }
1248}
1249
1250impl<'a> TryFrom<&'a [u8]> for SimplePseudonym {
1251 type Error = GeneralError;
1252
1253 fn try_from(value: &'a [u8]) -> result::Result<Self, Self::Error> {
1254 value
1255 .try_into()
1256 .map(Self)
1257 .map_err(|_| ParseError("SimplePseudonym".into()))
1258 }
1259}
1260
1261impl Randomizable for SimplePseudonym {
1262 fn random() -> Self {
1264 let mut data = vec![0u8; Self::SIZE];
1265 hopr_crypto_random::random_fill(&mut data);
1266 Self::try_from(data.as_slice()).unwrap()
1267 }
1268}
1269
1270impl Pseudonym for SimplePseudonym {}
1271
1272#[cfg(test)]
1273mod tests {
1274 use std::str::FromStr;
1275
1276 use ed25519_dalek::Signer;
1277 use hex_literal::hex;
1278 use hopr_primitive_types::prelude::*;
1279 use k256::{
1280 AffinePoint, NonZeroScalar, Secp256k1, U256,
1281 ecdsa::VerifyingKey,
1282 elliptic_curve::{CurveArithmetic, sec1::ToEncodedPoint},
1283 };
1284 use libp2p_identity::PeerId;
1285
1286 use crate::{
1287 keypairs::{ChainKeypair, Keypair, OffchainKeypair},
1288 types::{
1289 Challenge, CurvePoint, HalfKey, HalfKeyChallenge, Hash, OffchainPublicKey, OffchainSignature, PublicKey,
1290 Response, Signature,
1291 },
1292 utils::random_group_element,
1293 };
1294
1295 const PUBLIC_KEY: [u8; 33] = hex!("021464586aeaea0eb5736884ca1bf42d165fc8e2243b1d917130fb9e321d7a93b8");
1296 const PUBLIC_KEY_UNCOMPRESSED_PLAIN: [u8; 64] = hex!("1464586aeaea0eb5736884ca1bf42d165fc8e2243b1d917130fb9e321d7a93b8fb0699d4f177f9c84712f6d7c5f6b7f4f6916116047fa25c79ef806fc6c9523e");
1297 const PUBLIC_KEY_UNCOMPRESSED: [u8; 65] = hex!("041464586aeaea0eb5736884ca1bf42d165fc8e2243b1d917130fb9e321d7a93b8fb0699d4f177f9c84712f6d7c5f6b7f4f6916116047fa25c79ef806fc6c9523e");
1298 const PRIVATE_KEY: [u8; 32] = hex!("e17fe86ce6e99f4806715b0c9412f8dad89334bf07f72d5834207a9d8f19d7f8");
1299
1300 #[test]
1301 fn test_signature_signing() -> anyhow::Result<()> {
1302 let msg = b"test12345";
1303 let kp = ChainKeypair::from_secret(&PRIVATE_KEY)?;
1304 let sgn = Signature::sign_message(msg, &kp);
1305
1306 let expected_pk = PublicKey::try_from(PUBLIC_KEY.as_ref())?;
1307 assert!(sgn.verify_message(msg, &expected_pk));
1308
1309 let extracted_pk = PublicKey::from_signature(msg, &sgn)?;
1310 assert_eq!(expected_pk, extracted_pk, "key extracted from signature does not match");
1311
1312 Ok(())
1313 }
1314
1315 #[test]
1316 fn test_offchain_signature_signing() -> anyhow::Result<()> {
1317 let msg = b"test12345";
1318 let keypair = OffchainKeypair::from_secret(&PRIVATE_KEY)?;
1319
1320 let key = ed25519_dalek::SecretKey::try_from(PRIVATE_KEY)?;
1321 let kp = ed25519_dalek::SigningKey::from_bytes(&key);
1322 let pk = ed25519_dalek::VerifyingKey::from(&kp);
1323
1324 let sgn = kp.sign(msg);
1325 assert!(pk.verify_strict(msg, &sgn).is_ok(), "blomp");
1326
1327 let sgn_1 = OffchainSignature::sign_message(msg, &keypair);
1328 let sgn_2 = OffchainSignature::try_from(sgn_1.as_ref())?;
1329
1330 assert!(
1331 sgn_1.verify_message(msg, keypair.public()),
1332 "cannot verify message via sig 1"
1333 );
1334 assert!(
1335 sgn_2.verify_message(msg, keypair.public()),
1336 "cannot verify message via sig 2"
1337 );
1338 assert_eq!(sgn_1, sgn_2, "signatures must be equal");
1339
1340 Ok(())
1341 }
1342
1343 #[test]
1344 fn test_signature_serialize() -> anyhow::Result<()> {
1345 let msg = b"test000000";
1346 let kp = ChainKeypair::from_secret(&PRIVATE_KEY)?;
1347 let sgn = Signature::sign_message(msg, &kp);
1348
1349 let deserialized = Signature::try_from(sgn.as_ref())?;
1350 assert_eq!(sgn, deserialized, "signatures don't match");
1351
1352 Ok(())
1353 }
1354
1355 #[test]
1356 fn test_offchain_signature() -> anyhow::Result<()> {
1357 let msg = b"test12345";
1358 let keypair = OffchainKeypair::from_secret(&PRIVATE_KEY)?;
1359
1360 let key = ed25519_dalek::SecretKey::try_from(PRIVATE_KEY)?;
1361 let kp = ed25519_dalek::SigningKey::from_bytes(&key);
1362 let pk = ed25519_dalek::VerifyingKey::from(&kp);
1363
1364 let sgn = kp.sign(msg);
1365 assert!(pk.verify_strict(msg, &sgn).is_ok(), "blomp");
1366
1367 let sgn_1 = OffchainSignature::sign_message(msg, &keypair);
1368 let sgn_2 = OffchainSignature::try_from(sgn_1.as_ref())?;
1369
1370 assert!(
1371 sgn_1.verify_message(msg, keypair.public()),
1372 "cannot verify message via sig 1"
1373 );
1374 assert!(
1375 sgn_2.verify_message(msg, keypair.public()),
1376 "cannot verify message via sig 2"
1377 );
1378 assert_eq!(sgn_1, sgn_2, "signatures must be equal");
1379 Ok(())
1386 }
1387
1388 #[test]
1389 fn test_public_key_to_hex() -> anyhow::Result<()> {
1390 let pk = PublicKey::from_privkey(&hex!(
1391 "492057cf93e99b31d2a85bc5e98a9c3aa0021feec52c227cc8170e8f7d047775"
1392 ))?;
1393
1394 assert_eq!("0x39d1bc2291826eaed86567d225cf243ebc637275e0a5aedb0d6b1dc82136a38e428804340d4c949a029846f682711d046920b4ca8b8ebeb9d1192b5bdaa54dba",
1395 pk.to_hex(false));
1396 assert_eq!(
1397 "0x0239d1bc2291826eaed86567d225cf243ebc637275e0a5aedb0d6b1dc82136a38e",
1398 pk.to_hex(true)
1399 );
1400
1401 Ok(())
1402 }
1403
1404 #[test]
1405 fn test_public_key_recover() -> anyhow::Result<()> {
1406 let address = Address::from_str("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266")?;
1407
1408 let r = hex!("bcae4d37e3a1cd869984d1d68f9242291773cd33d26f1e754ecc1a9bfaee7d17");
1409 let s = hex!("0b755ab5f6375595fc7fc245c45f6598cc873719183733f4c464d63eefd8579b");
1410 let v = 1u8;
1411
1412 let hash = hex!("fac7acad27047640b069e8157b61623e3cb6bb86e6adf97151f93817c291f3cf");
1413
1414 assert_eq!(
1415 address,
1416 PublicKey::from_raw_signature(&hash, &r, &s, v, VerifyingKey::recover_from_prehash)?.to_address()
1417 );
1418
1419 Ok(())
1420 }
1421
1422 #[test]
1423 fn test_public_key_combine_tweak() -> anyhow::Result<()> {
1424 let (scalar1, point1) = random_group_element();
1425 let (scalar2, point2) = random_group_element();
1426
1427 let pk1 = PublicKey::try_from(point1)?;
1428 let pk2 = PublicKey::try_from(point2)?;
1429
1430 let sum = PublicKey::combine(&[&pk1, &pk2]);
1431 let tweak1 = PublicKey::tweak_add(&pk1, &scalar2);
1432 assert_eq!(sum, tweak1);
1433
1434 let tweak2 = PublicKey::tweak_add(&pk2, &scalar1);
1435 assert_eq!(sum, tweak2);
1436
1437 Ok(())
1438 }
1439
1440 #[test]
1441 fn test_sign_and_recover() -> anyhow::Result<()> {
1442 let msg = hex!("eff80b9f035b1d369c6a60f362ac7c8b8c3b61b76d151d1be535145ccaa3e83e");
1443
1444 let kp = ChainKeypair::from_secret(&PRIVATE_KEY)?;
1445
1446 let signature1 = Signature::sign_message(&msg, &kp);
1447 let signature2 = Signature::sign_hash(&msg, &kp);
1448
1449 let pub_key1 = PublicKey::from_privkey(&PRIVATE_KEY)?;
1450 let pub_key2 = PublicKey::from_signature(&msg, &signature1)?;
1451 let pub_key3 = PublicKey::from_signature_hash(&msg, &signature2)?;
1452
1453 assert_eq!(pub_key1, kp.public().0);
1454 assert_eq!(pub_key1, pub_key2, "recovered public key does not match");
1455 assert_eq!(pub_key1, pub_key3, "recovered public key does not match");
1456
1457 assert!(
1458 signature1.verify_message(&msg, &pub_key1),
1459 "signature 1 verification failed with pub key 1"
1460 );
1461 assert!(
1462 signature1.verify_message(&msg, &pub_key2),
1463 "signature 1 verification failed with pub key 2"
1464 );
1465 assert!(
1466 signature1.verify_message(&msg, &pub_key3),
1467 "signature 1 verification failed with pub key 3"
1468 );
1469
1470 assert!(
1471 signature2.verify_hash(&msg, &pub_key1),
1472 "signature 2 verification failed with pub key 1"
1473 );
1474 assert!(
1475 signature2.verify_hash(&msg, &pub_key2),
1476 "signature 2 verification failed with pub key 2"
1477 );
1478 assert!(
1479 signature2.verify_hash(&msg, &pub_key3),
1480 "signature 2 verification failed with pub key 3"
1481 );
1482
1483 Ok(())
1484 }
1485
1486 #[test]
1487 fn test_public_key_serialize() -> anyhow::Result<()> {
1488 let pk1 = PublicKey::try_from(PUBLIC_KEY.as_ref())?;
1489 let pk2 = PublicKey::try_from(pk1.to_bytes(true).as_ref())?;
1490 let pk3 = PublicKey::try_from(pk1.to_bytes(false).as_ref())?;
1491
1492 assert_eq!(pk1, pk2, "pub keys 1 2 don't match");
1493 assert_eq!(pk2, pk3, "pub keys 2 3 don't match");
1494
1495 let pk1 = PublicKey::try_from(PUBLIC_KEY.as_ref())?;
1496 let pk2 = PublicKey::try_from(PUBLIC_KEY_UNCOMPRESSED.as_ref())?;
1497 let pk3 = PublicKey::try_from(PUBLIC_KEY_UNCOMPRESSED_PLAIN.as_ref())?;
1498
1499 assert_eq!(pk1, pk2, "pubkeys don't match");
1500 assert_eq!(pk2, pk3, "pubkeys don't match");
1501
1502 assert_eq!(PublicKey::SIZE_COMPRESSED, pk1.to_bytes(true).len());
1503 assert_eq!(PublicKey::SIZE_UNCOMPRESSED, pk1.to_bytes(false).len());
1504
1505 let shorter = hex!("f85e38b056284626a7aed0acc5d474605a408e6cccf76d7241ec7b4dedb31929b710e034f4f9a7dba97743b01e1cc35a45a60bebb29642cb0ba6a7fe8433316c");
1506 let s1 = PublicKey::try_from(shorter.as_ref())?;
1507 let s2 = PublicKey::try_from(s1.to_bytes(false).as_ref())?;
1508 assert_eq!(s1, s2);
1509
1510 Ok(())
1511 }
1512
1513 #[test]
1514 fn test_public_key_should_not_accept_identity() -> anyhow::Result<()> {
1515 let cp: CurvePoint = AffinePoint::IDENTITY.into();
1516
1517 PublicKey::try_from(cp).expect_err("must fail for identity point");
1518 PublicKey::try_from(AffinePoint::IDENTITY).expect_err("must fail for identity point");
1519
1520 Ok(())
1521 }
1522
1523 #[test]
1524 fn test_public_key_curve_point() -> anyhow::Result<()> {
1525 let cp1: CurvePoint = PublicKey::try_from(PUBLIC_KEY.as_ref())?.into();
1526 let cp2 = CurvePoint::try_from(cp1.as_ref())?;
1527 assert_eq!(cp1, cp2);
1528
1529 Ok(())
1530 }
1531
1532 #[test]
1533 fn test_public_key_from_privkey() -> anyhow::Result<()> {
1534 let pk1 = PublicKey::from_privkey(&PRIVATE_KEY)?;
1535 let pk2 = PublicKey::try_from(PUBLIC_KEY.as_ref())?;
1536
1537 assert_eq!(pk1, pk2, "failed to match deserialized pub key");
1538
1539 Ok(())
1540 }
1541
1542 #[test]
1543 fn test_offchain_public_key() -> anyhow::Result<()> {
1544 let (s, pk1) = OffchainKeypair::random().unzip();
1545
1546 let pk2 = OffchainPublicKey::from_privkey(s.as_ref())?;
1547 assert_eq!(pk1, pk2, "from privkey failed");
1548
1549 let pk3 = OffchainPublicKey::try_from(pk1.as_ref())?;
1550 assert_eq!(pk1, pk3, "from bytes failed");
1551
1552 Ok(())
1553 }
1554
1555 #[test]
1556 fn test_offchain_public_key_peerid() -> anyhow::Result<()> {
1557 let valid_peerid = PeerId::from_str("12D3KooWLYKsvDB4xEELYoHXxeStj2gzaDXjra2uGaFLpKCZkJHs")?;
1558 let valid = OffchainPublicKey::try_from(valid_peerid)?;
1559 assert_eq!(valid_peerid, valid.into(), "must work with ed25519 peer ids");
1560
1561 let invalid_peerid = PeerId::from_str("16Uiu2HAmPHGyJ7y1Rj3kJ64HxJQgM9rASaeT2bWfXF9EiX3Pbp3K")?;
1562 let invalid = OffchainPublicKey::try_from(invalid_peerid);
1563 assert!(invalid.is_err(), "must not work with secp256k1 peer ids");
1564
1565 let invalid_peerid_2 = PeerId::from_str("QmWvEwidPYBbLHfcZN6ATHdm4NPM4KbUx72LZnZRoRNKEN")?;
1566 let invalid_2 = OffchainPublicKey::try_from(invalid_peerid_2);
1567 assert!(invalid_2.is_err(), "must not work with rsa peer ids");
1568
1569 Ok(())
1570 }
1571
1572 #[test]
1573 pub fn test_response() -> anyhow::Result<()> {
1574 let r1 = Response([0u8; Response::SIZE]);
1575 let r2 = Response::try_from(r1.as_ref())?;
1576 assert_eq!(r1, r2, "deserialized response does not match");
1577
1578 Ok(())
1579 }
1580
1581 #[test]
1582 fn test_curve_point() -> anyhow::Result<()> {
1583 let scalar = NonZeroScalar::from_uint(U256::from_u8(100)).expect("should hold a value");
1584 let test_point = (<Secp256k1 as CurveArithmetic>::ProjectivePoint::GENERATOR * scalar.as_ref()).to_affine();
1585
1586 let cp1 = CurvePoint::from_str(hex::encode(test_point.to_encoded_point(false).to_bytes()).as_str())?;
1587
1588 let cp2 = CurvePoint::try_from(cp1.as_ref())?;
1589
1590 assert_eq!(cp1, cp2, "failed to match deserialized curve point");
1591
1592 let pk = PublicKey::from_privkey(&scalar.to_bytes())?;
1593
1594 assert_eq!(
1595 cp1.to_address(),
1596 pk.to_address(),
1597 "failed to match curve point address with pub key address"
1598 );
1599
1600 let ch1 = Challenge(cp1);
1601 let ch2 = Challenge(cp2);
1602
1603 assert_eq!(ch1.to_ethereum_challenge(), ch2.to_ethereum_challenge());
1604 assert_eq!(ch1, ch2, "failed to match ethereum challenges from curve points");
1605
1606 let scalar2 = NonZeroScalar::from_uint(U256::from_u8(123)).expect("should hold a value");
1608 let test_point2 = (<Secp256k1 as CurveArithmetic>::ProjectivePoint::GENERATOR * scalar2.as_ref()).to_affine();
1609 let uncompressed = test_point2.to_encoded_point(false);
1610 assert!(!uncompressed.is_compressed(), "given point is compressed");
1611
1612 let compressed = uncompressed.compress();
1613 assert!(compressed.is_compressed(), "failed to compress points");
1614
1615 let cp3 = CurvePoint::try_from(uncompressed.as_bytes())?;
1616 let cp4 = CurvePoint::try_from(compressed.as_bytes())?;
1617
1618 assert_eq!(
1619 cp3, cp4,
1620 "failed to match curve point from compressed and uncompressed source"
1621 );
1622
1623 Ok(())
1624 }
1625
1626 #[test]
1627 fn test_half_key() -> anyhow::Result<()> {
1628 let hk1 = HalfKey([0u8; HalfKey::SIZE]);
1629 let hk2 = HalfKey::try_from(hk1.as_ref())?;
1630
1631 assert_eq!(hk1, hk2, "failed to match deserialized half-key");
1632
1633 Ok(())
1634 }
1635
1636 #[test]
1637 fn test_half_key_challenge() -> anyhow::Result<()> {
1638 let hkc1 = HalfKeyChallenge::try_from(PUBLIC_KEY.as_ref())?;
1639 let hkc2 = HalfKeyChallenge::try_from(hkc1.as_ref())?;
1640 assert_eq!(hkc1, hkc2, "failed to match deserialized half key challenge");
1641
1642 Ok(())
1643 }
1644
1645 #[test]
1646 fn test_hash() -> anyhow::Result<()> {
1647 let hash1 = Hash::create(&[b"msg"]);
1648 assert_eq!(
1649 "0x92aef1b955b9de564fc50e31a55b470b0c8cdb931f186485d620729fb03d6f2c",
1650 hash1.to_hex(),
1651 "hash test vector failed to match"
1652 );
1653
1654 let hash2 = Hash::try_from(hash1.as_ref())?;
1655 assert_eq!(hash1, hash2, "failed to match deserialized hash");
1656
1657 assert_eq!(
1658 hash1.hash(),
1659 Hash::try_from(hex!("1c4d8d521eccee7225073ea180e0fa075a6443afb7ca06076a9566b07d29470f").as_ref())?
1660 );
1661
1662 Ok(())
1663 }
1664}