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