lit_node_core/models/
peer_id.rs

1use crate::{Error, Result};
2use lit_rust_crypto::{
3    blsful::inner_types as bls,
4    curve25519_dalek, decaf377,
5    ed448_goldilocks::{self, sha3},
6    elliptic_curve::{
7        bigint::{
8            ArrayEncoding, ByteArray, Encoding, NonZero, Random, RandomMod, U256, U512, U768, U896,
9        },
10        ops::Reduce,
11        rand_core::{CryptoRng, RngCore},
12        scalar::FromUintUnchecked,
13    },
14    jubjub,
15    k256::{
16        self,
17        sha2::{self, Digest},
18    },
19    p256, p384, pallas, vsss_rs,
20};
21use serde::{Deserialize, Deserializer, Serialize, Serializer};
22use std::fmt::{self, Debug, Display, Formatter};
23use std::hash::{Hash, Hasher};
24use std::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize};
25use std::str::FromStr;
26
27macro_rules! from_impl_peer_id {
28    ($($primitive:ident),+$(,)*) => {
29        $(
30            impl TryFrom<$primitive> for PeerId {
31                type Error = Error;
32
33                fn try_from(value: $primitive) -> Result<Self> {
34                    PeerId::try_from(U256::from(value))
35                }
36            }
37        )+
38    };
39}
40
41macro_rules! from_impl_nonzero_peer_id {
42    ($($nonzero:ident => $primitive:ident),+$(,)*) => {
43        $(
44            impl TryFrom<PeerId> for $nonzero {
45                type Error = Error;
46
47                fn try_from(value: PeerId) -> Result<Self> {
48                    let value = $primitive::try_from(value)?;
49                    $nonzero::new(value).ok_or_else(|| Error::Parse("PeerId is zero".to_string()))
50                }
51            }
52
53            impl TryFrom<&PeerId> for $nonzero {
54                type Error = Error;
55
56                fn try_from(value: &PeerId) -> Result<Self> {
57                    Self::try_from(*value)
58                }
59            }
60        )+
61    };
62}
63
64from_impl_peer_id!(u128, u64, u32, u16, u8);
65from_impl_nonzero_peer_id!(
66    NonZeroUsize => usize,
67    NonZeroU128 => u128,
68    NonZeroU64 => u64,
69    NonZeroU32 => u32,
70    NonZeroU16 => u16,
71    NonZeroU8 => u8,
72);
73
74pub trait FromPeerIdDirect {
75    fn from_peer_id(peer_id: PeerId) -> Self;
76}
77
78/// PeerId is a unique identifier for a peer.
79/// This represents a 256-bit number that can be compared, sorted, and hashed
80/// rather than an address or random byte sequence.
81/// Ideally, this is generated when the node peer is created and never changes.
82/// 256-bits is more than enough to guarantee uniqueness. So why 256-bits?
83/// Most protocols operate on ECC-scalars which are at least 256-bits.
84/// This allows us to use the same data type for the peer id and the ECC scalar.
85#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
86#[repr(transparent)]
87pub struct PeerId(pub NonZero<U256>);
88
89impl Serialize for PeerId {
90    fn serialize<S>(&self, s: S) -> std::result::Result<S::Ok, S::Error>
91    where
92        S: Serializer,
93    {
94        if s.is_human_readable() {
95            s.serialize_str(&self.to_string())
96        } else {
97            s.serialize_bytes(&self.0.to_be_byte_array())
98        }
99    }
100}
101
102impl<'de> Deserialize<'de> for PeerId {
103    fn deserialize<D>(d: D) -> std::result::Result<Self, D::Error>
104    where
105        D: Deserializer<'de>,
106    {
107        if d.is_human_readable() {
108            let value = <&str>::deserialize(d)?;
109            value.parse().map_err(serde::de::Error::custom)
110        } else {
111            let bytes = Vec::<u8>::deserialize(d)?;
112            PeerId::from_slice(&bytes).map_err(serde::de::Error::custom)
113        }
114    }
115}
116
117impl Default for PeerId {
118    fn default() -> Self {
119        PeerId::NOT_ASSIGNED
120    }
121}
122
123impl Hash for PeerId {
124    fn hash<H: Hasher>(&self, state: &mut H) {
125        (*self.0).hash(state);
126    }
127}
128
129impl TryFrom<U256> for PeerId {
130    type Error = Error;
131
132    fn try_from(value: U256) -> Result<Self> {
133        Option::<PeerId>::from(NonZero::new(value).map(PeerId))
134            .ok_or_else(|| Error::Parse("PeerId is zero".to_string()))
135    }
136}
137
138impl TryFrom<&U256> for PeerId {
139    type Error = Error;
140
141    fn try_from(value: &U256) -> Result<Self> {
142        PeerId::try_from(*value)
143    }
144}
145
146impl From<PeerId> for U256 {
147    fn from(value: PeerId) -> Self {
148        *value.0
149    }
150}
151
152impl From<&PeerId> for U256 {
153    fn from(value: &PeerId) -> Self {
154        *value.0
155    }
156}
157
158impl From<PeerId> for ethers::types::U256 {
159    fn from(value: PeerId) -> Self {
160        ethers::types::U256::from(value.0.to_be_bytes())
161    }
162}
163
164impl TryFrom<ethers::types::U256> for PeerId {
165    type Error = Error;
166    fn try_from(value: ethers::types::U256) -> Result<Self> {
167        #[cfg(target_pointer_width = "32")]
168        {
169            Self::try_from(U256::from_words([
170                value.0[0] as u32,
171                (value.0[0] >> 32) as u32,
172                value.0[1] as u32,
173                (value.0[1] >> 32) as u32,
174                value.0[2] as u32,
175                (value.0[2] >> 32) as u32,
176                value.0[3] as u32,
177                (value.0[3] >> 32) as u32,
178            ]))
179        }
180        #[cfg(target_pointer_width = "64")]
181        Self::try_from(U256::from_words(value.0))
182    }
183}
184
185impl TryFrom<usize> for PeerId {
186    type Error = Error;
187
188    fn try_from(value: usize) -> Result<Self> {
189        PeerId::try_from(U256::from_u64(value as u64))
190    }
191}
192
193impl From<NonZeroU128> for PeerId {
194    fn from(value: NonZeroU128) -> Self {
195        PeerId(NonZero::from(value))
196    }
197}
198
199impl From<NonZeroU64> for PeerId {
200    fn from(value: NonZeroU64) -> Self {
201        PeerId(NonZero::from(value))
202    }
203}
204
205impl From<NonZeroU32> for PeerId {
206    fn from(value: NonZeroU32) -> Self {
207        PeerId(NonZero::from(value))
208    }
209}
210
211impl From<NonZeroU16> for PeerId {
212    fn from(value: NonZeroU16) -> Self {
213        PeerId(NonZero::from(value))
214    }
215}
216
217impl From<NonZeroU8> for PeerId {
218    fn from(value: NonZeroU8) -> Self {
219        PeerId(NonZero::from(value))
220    }
221}
222
223impl TryFrom<PeerId> for usize {
224    type Error = Error;
225
226    fn try_from(value: PeerId) -> Result<Self> {
227        if value.0.bits() > 64 {
228            return Err(Error::Parse(format!(
229                "PeerId too large to convert to usize: {}",
230                value.0
231            )));
232        }
233        Ok(value.0.as_words()[0] as usize)
234    }
235}
236
237impl TryFrom<&PeerId> for usize {
238    type Error = Error;
239
240    fn try_from(value: &PeerId) -> Result<Self> {
241        Self::try_from(*value)
242    }
243}
244
245impl TryFrom<PeerId> for u128 {
246    type Error = Error;
247
248    fn try_from(value: PeerId) -> Result<Self> {
249        if value.0.bits() > 128 {
250            return Err(Error::Parse(format!(
251                "PeerId too large to convert to u128: {}",
252                value.0
253            )));
254        }
255        let words = value.0.as_words();
256        Ok((words[0] as u128) | ((words[1] as u128) << 64))
257    }
258}
259
260impl TryFrom<&PeerId> for u128 {
261    type Error = Error;
262
263    fn try_from(value: &PeerId) -> Result<Self> {
264        Self::try_from(*value)
265    }
266}
267
268impl TryFrom<PeerId> for u64 {
269    type Error = Error;
270
271    fn try_from(value: PeerId) -> Result<Self> {
272        if value.0.bits() > 64 {
273            return Err(Error::Parse(format!(
274                "PeerId too large to convert to u64: {}",
275                value.0
276            )));
277        }
278        #[cfg(target_pointer_width = "32")]
279        {
280            let words = value.0.as_words();
281            Ok((words[0] as u64) | ((words[1] as u64) << 32))
282        }
283        #[cfg(target_pointer_width = "64")]
284        Ok(value.0.as_words()[0])
285    }
286}
287
288impl TryFrom<&PeerId> for u64 {
289    type Error = Error;
290
291    fn try_from(value: &PeerId) -> Result<Self> {
292        Self::try_from(*value)
293    }
294}
295
296impl TryFrom<PeerId> for u32 {
297    type Error = Error;
298
299    fn try_from(value: PeerId) -> Result<Self> {
300        value.0.as_words()[0].try_into().map_err(|_| Error::Parse(format!("unable to convert PeerId '{}' to 32-bit integer. PeerId is too large to convert to u32", value)))
301    }
302}
303
304impl TryFrom<&PeerId> for u32 {
305    type Error = Error;
306
307    fn try_from(value: &PeerId) -> Result<Self> {
308        Self::try_from(*value)
309    }
310}
311
312impl TryFrom<PeerId> for u16 {
313    type Error = Error;
314
315    fn try_from(value: PeerId) -> Result<Self> {
316        value.0.as_words()[0].try_into().map_err(|_| Error::Parse(format!("unable to convert PeerId '{}' to 16-bit integer. PeerId is too large to convert to u16", value)))
317    }
318}
319
320impl TryFrom<&PeerId> for u16 {
321    type Error = Error;
322
323    fn try_from(value: &PeerId) -> Result<Self> {
324        Self::try_from(*value)
325    }
326}
327
328impl TryFrom<PeerId> for u8 {
329    type Error = Error;
330
331    fn try_from(value: PeerId) -> Result<Self> {
332        value.0.as_words()[0].try_into().map_err(|_| Error::Parse(format!("unable to convert PeerId '{}' to 8-bit integer. PeerId is too large to convert to u8", value)))
333    }
334}
335
336impl TryFrom<&PeerId> for u8 {
337    type Error = Error;
338
339    fn try_from(value: &PeerId) -> Result<Self> {
340        Self::try_from(*value)
341    }
342}
343
344impl TryFrom<Vec<u8>> for PeerId {
345    type Error = Error;
346
347    fn try_from(value: Vec<u8>) -> Result<Self> {
348        Self::try_from(value.as_slice())
349    }
350}
351
352impl TryFrom<&Vec<u8>> for PeerId {
353    type Error = Error;
354
355    fn try_from(value: &Vec<u8>) -> Result<Self> {
356        Self::try_from(value.as_slice())
357    }
358}
359
360impl TryFrom<&[u8]> for PeerId {
361    type Error = Error;
362
363    fn try_from(value: &[u8]) -> Result<Self> {
364        Self::from_slice(value)
365    }
366}
367
368impl TryFrom<Box<[u8]>> for PeerId {
369    type Error = Error;
370
371    fn try_from(value: Box<[u8]>) -> Result<Self> {
372        Self::try_from(value.as_ref())
373    }
374}
375
376impl TryFrom<&[u8; 32]> for PeerId {
377    type Error = Error;
378
379    fn try_from(value: &[u8; 32]) -> Result<Self> {
380        Ok(PeerId::from_be_slice(value))
381    }
382}
383
384impl TryFrom<[u8; 32]> for PeerId {
385    type Error = Error;
386    fn try_from(value: [u8; 32]) -> Result<Self> {
387        Ok(PeerId::from_be_slice(&value))
388    }
389}
390
391impl TryFrom<&ByteArray<U256>> for PeerId {
392    type Error = Error;
393
394    fn try_from(value: &ByteArray<U256>) -> Result<Self> {
395        Self::try_from(*value)
396    }
397}
398
399impl TryFrom<ByteArray<U256>> for PeerId {
400    type Error = Error;
401
402    fn try_from(value: ByteArray<U256>) -> Result<Self> {
403        PeerId::try_from(U256::from_be_byte_array(value))
404    }
405}
406
407impl From<PeerId> for Vec<u8> {
408    fn from(value: PeerId) -> Self {
409        value.0.to_be_byte_array().to_vec()
410    }
411}
412
413impl From<&PeerId> for Vec<u8> {
414    fn from(value: &PeerId) -> Self {
415        value.0.to_be_byte_array().to_vec()
416    }
417}
418
419impl Debug for PeerId {
420    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
421        if self == &PeerId::NOT_ASSIGNED {
422            return write!(f, "PeerId({})", self);
423        }
424        write!(f, "PeerId(NonZero(Uint({}))", self)
425    }
426}
427
428impl Display for PeerId {
429    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
430        if self == &PeerId::NOT_ASSIGNED {
431            return write!(f, "NotAssigned");
432        }
433        // Trim the leading zeros if any
434        let bytes = self.0.to_be_byte_array();
435        let mut index = bytes.len() - 1;
436        for (i, byte) in bytes.iter().enumerate() {
437            if *byte != 0 {
438                index = i;
439                break;
440            }
441        }
442        let output = hex::encode(&bytes[index..]);
443        index = output.chars().position(|c| c != '0').unwrap_or(0);
444        write!(f, "{}", &output[index..])
445    }
446}
447
448impl FromStr for PeerId {
449    type Err = Error;
450
451    fn from_str(s: &str) -> Result<Self> {
452        if s.len() > 64 {
453            return Err(Error::Parse(format!(
454                "PeerId too large to convert from string: PeerId: {}",
455                s
456            )));
457        }
458        let mut padded = s.to_string();
459        if padded.len() & 1 == 1 {
460            padded.insert(0, '0');
461        }
462        let bytes = hex::decode(padded)?;
463        let mut array = [0u8; 32];
464        let start = array.len().saturating_sub(bytes.len());
465        array[start..].copy_from_slice(&bytes);
466        PeerId::try_from(U256::from_be_slice(&array))
467    }
468}
469
470impl From<PeerId> for k256::Scalar {
471    fn from(value: PeerId) -> Self {
472        let digest = sha2::Sha512::digest(value.0.to_be_byte_array());
473        <k256::Scalar as Reduce<U512>>::reduce(U512::from_be_byte_array(digest))
474    }
475}
476
477impl From<PeerId> for k256::NonZeroScalar {
478    fn from(value: PeerId) -> Self {
479        let scalar = k256::Scalar::from(value);
480        k256::NonZeroScalar::new(scalar).expect("scalar is somehow zero")
481    }
482}
483
484impl From<PeerId> for p256::Scalar {
485    fn from(value: PeerId) -> Self {
486        const N: NonZero<U512> = NonZero::from_uint(U512::from_be_hex(
487            "0000000000000000000000000000000000000000000000000000000000000000ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
488        ));
489        let digest = sha2::Sha512::digest(value.0.to_be_byte_array());
490        let wide_value = U512::from_be_byte_array(digest);
491        let scalar = wide_value % N;
492        let (_, lo) = scalar.split();
493
494        p256::Scalar::from_uint_unchecked(lo)
495    }
496}
497
498impl From<PeerId> for p256::NonZeroScalar {
499    fn from(value: PeerId) -> Self {
500        let scalar = p256::Scalar::from(value);
501        p256::NonZeroScalar::new(scalar).expect("scalar is somehow zero")
502    }
503}
504
505impl From<PeerId> for curve25519_dalek::Scalar {
506    fn from(value: PeerId) -> Self {
507        let digest = sha2::Sha512::digest(value.0.to_be_byte_array());
508        let digest: [u8; 64] = digest
509            .as_slice()
510            .try_into()
511            .expect("digest is the wrong length");
512        curve25519_dalek::Scalar::from_bytes_mod_order_wide(&digest)
513    }
514}
515
516impl From<PeerId> for vsss_rs::curve25519::WrappedScalar {
517    fn from(value: PeerId) -> Self {
518        let digest = sha2::Sha512::digest(value.0.to_be_byte_array());
519        let digest: [u8; 64] = digest
520            .as_slice()
521            .try_into()
522            .expect("digest is the wrong length");
523        Self(vsss_rs::curve25519_dalek::Scalar::from_bytes_mod_order_wide(&digest))
524    }
525}
526
527impl From<PeerId> for p384::Scalar {
528    fn from(value: PeerId) -> Self {
529        use sha3::digest::{ExtendableOutput, Update};
530        const N: NonZero<U768> = NonZero::from_uint(U768::from_be_hex(
531            "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973",
532        ));
533        let mut hasher = sha3::Shake128::default();
534        hasher.update(&value.0.to_be_byte_array());
535        let digest = hasher.finalize_boxed(96);
536        let wide_value = U768::from_be_slice(digest.as_ref());
537
538        let scalar = wide_value % N;
539        let (_, lo) = scalar.split();
540        p384::Scalar::from_uint_unchecked(lo)
541    }
542}
543
544impl From<PeerId> for p384::NonZeroScalar {
545    fn from(value: PeerId) -> Self {
546        let scalar = p384::Scalar::from(value);
547        p384::NonZeroScalar::new(scalar).expect("scalar is somehow zero")
548    }
549}
550
551impl From<PeerId> for ed448_goldilocks::Scalar {
552    fn from(value: PeerId) -> Self {
553        use sha3::digest::{ExtendableOutput, Update};
554
555        let mut hasher = sha3::Shake128::default();
556        hasher.update(&value.0.to_be_byte_array());
557        let digest = hasher.finalize_boxed(114);
558        let wide_bytes = ed448_goldilocks::WideScalarBytes::from_slice(digest.as_ref());
559        <ed448_goldilocks::Scalar as Reduce<U896>>::reduce_bytes(wide_bytes)
560    }
561}
562
563impl From<PeerId> for jubjub::Scalar {
564    fn from(value: PeerId) -> Self {
565        let digest = sha2::Sha512::digest(value.0.to_be_byte_array());
566        <jubjub::Scalar as Reduce<U512>>::reduce(U512::from_be_byte_array(digest))
567    }
568}
569
570impl From<PeerId> for bls::Scalar {
571    fn from(value: PeerId) -> Self {
572        let digest = sha2::Sha512::digest(value.0.to_be_byte_array());
573        <bls::Scalar as Reduce<U512>>::reduce(U512::from_be_byte_array(digest))
574    }
575}
576
577impl From<PeerId> for decaf377::Fr {
578    fn from(value: PeerId) -> Self {
579        let digest = sha2::Sha512::digest(value.0.to_be_byte_array());
580        Self::from_le_bytes_mod_order(&digest)
581    }
582}
583
584impl From<PeerId> for pallas::Scalar {
585    fn from(value: PeerId) -> Self {
586        let digest = sha2::Sha512::digest(value.0.to_be_byte_array());
587        let n = U512::from_be_byte_array(digest);
588        Self::reduce(n)
589    }
590}
591
592impl FromPeerIdDirect for k256::Scalar {
593    fn from_peer_id(peer_id: PeerId) -> Self {
594        Self::from_uint_unchecked(*peer_id.0.as_ref())
595    }
596}
597
598impl FromPeerIdDirect for k256::NonZeroScalar {
599    fn from_peer_id(peer_id: PeerId) -> Self {
600        let scalar = k256::Scalar::from_peer_id(peer_id);
601        // clippy error
602        #[allow(dead_code)]
603        struct NZScalar {
604            scalar: k256::Scalar,
605        }
606        let t = NZScalar { scalar };
607        unsafe { std::mem::transmute(t) }
608    }
609}
610
611impl FromPeerIdDirect for p256::Scalar {
612    fn from_peer_id(peer_id: PeerId) -> Self {
613        Self::from_uint_unchecked(*peer_id.0.as_ref())
614    }
615}
616
617impl FromPeerIdDirect for p256::NonZeroScalar {
618    fn from_peer_id(peer_id: PeerId) -> Self {
619        let scalar = p256::Scalar::from_peer_id(peer_id);
620        // clippy error
621        #[allow(dead_code)]
622        struct NZScalar {
623            scalar: p256::Scalar,
624        }
625        let t = NZScalar { scalar };
626        unsafe { std::mem::transmute(t) }
627    }
628}
629
630impl FromPeerIdDirect for p384::Scalar {
631    fn from_peer_id(peer_id: PeerId) -> Self {
632        Self::from_uint_unchecked(peer_id.0.as_ref().resize())
633    }
634}
635
636impl FromPeerIdDirect for p384::NonZeroScalar {
637    fn from_peer_id(peer_id: PeerId) -> Self {
638        let scalar = p384::Scalar::from_peer_id(peer_id);
639        // clippy error
640        #[allow(dead_code)]
641        struct NZScalar {
642            scalar: p384::Scalar,
643        }
644        let t = NZScalar { scalar };
645        unsafe { std::mem::transmute(t) }
646    }
647}
648
649impl FromPeerIdDirect for curve25519_dalek::Scalar {
650    fn from_peer_id(peer_id: PeerId) -> Self {
651        Self::from_uint_unchecked(*peer_id.0.as_ref())
652    }
653}
654
655impl FromPeerIdDirect for vsss_rs::curve25519::WrappedScalar {
656    fn from_peer_id(peer_id: PeerId) -> Self {
657        Self::from_uint_unchecked(*peer_id.0.as_ref())
658    }
659}
660
661impl FromPeerIdDirect for ed448_goldilocks::Scalar {
662    fn from_peer_id(peer_id: PeerId) -> Self {
663        Self::from_uint_unchecked(peer_id.0.as_ref().resize())
664    }
665}
666
667impl FromPeerIdDirect for bls::Scalar {
668    fn from_peer_id(peer_id: PeerId) -> Self {
669        Self::from_uint_unchecked(peer_id.0.as_ref().resize())
670    }
671}
672
673impl FromPeerIdDirect for jubjub::Scalar {
674    fn from_peer_id(peer_id: PeerId) -> Self {
675        #[cfg(target_pointer_width = "32")]
676        {
677            let words = *peer_id.0.as_ref().as_words();
678            let raw_words = [
679                words[0] as u64 | (words[1] as u64) << 32,
680                words[2] as u64 | (words[3] as u64) << 32,
681                words[4] as u64 | (words[5] as u64) << 32,
682                words[6] as u64 | (words[7] as u64) << 32,
683            ];
684            Self::from_raw(raw_words)
685        }
686        #[cfg(target_pointer_width = "64")]
687        Self::from_raw(*peer_id.0.as_ref().as_words())
688    }
689}
690
691impl FromPeerIdDirect for decaf377::Fr {
692    fn from_peer_id(peer_id: PeerId) -> Self {
693        let bytes = peer_id.0.as_ref().to_le_bytes();
694        Self::from_bytes_checked(&bytes).expect("to be small enough to work")
695    }
696}
697
698impl FromPeerIdDirect for pallas::Scalar {
699    fn from_peer_id(peer_id: PeerId) -> Self {
700        Self::from_uint_unchecked(*peer_id.0.as_ref())
701    }
702}
703
704impl PeerId {
705    pub const ONE: Self = PeerId(NonZero::<U256>::ONE);
706    pub const NOT_ASSIGNED: Self = PeerId(NonZero::<U256>::from_uint(U256::MAX));
707
708    pub fn is_not_assigned(&self) -> bool {
709        self.0 == Self::NOT_ASSIGNED.0
710    }
711
712    pub const fn from_u8(value: u8) -> Self {
713        PeerId(NonZero::<U256>::from_uint(U256::from_u8(value)))
714    }
715
716    pub const fn from_u16(value: u16) -> Self {
717        PeerId(NonZero::<U256>::from_uint(U256::from_u16(value)))
718    }
719
720    pub const fn from_u32(value: u32) -> Self {
721        PeerId(NonZero::<U256>::from_uint(U256::from_u32(value)))
722    }
723
724    pub const fn from_u64(value: u64) -> Self {
725        PeerId(NonZero::<U256>::from_uint(U256::from_u64(value)))
726    }
727
728    pub const fn from_u128(value: u128) -> Self {
729        PeerId(NonZero::<U256>::from_uint(U256::from_u128(value)))
730    }
731
732    pub const fn from_usize(value: usize) -> Self {
733        PeerId(NonZero::<U256>::from_uint(U256::from_u64(value as u64)))
734    }
735
736    /// Create a PeerId from a 256-bit value
737    pub const fn from_be_slice(bytes: &[u8; 32]) -> Self {
738        Self(NonZero::from_uint(U256::from_be_slice(bytes)))
739    }
740
741    pub fn from_slice(value: &[u8]) -> Result<Self> {
742        if value.is_empty() {
743            return Err(Error::Parse("PeerId slice cannot be empty".to_string()));
744        }
745        let array = if value.len() > 32 {
746            sha2::Sha512_256::digest(value).into()
747        } else {
748            let start = 32usize.saturating_sub(value.len());
749            let mut array = [0u8; 32];
750            array[start..].copy_from_slice(value);
751            array
752        };
753        PeerId::try_from(U256::from_be_slice(&array))
754    }
755
756    pub fn random(mut rng: impl RngCore + CryptoRng) -> Self {
757        PeerId(NonZero::<U256>::from_uint(U256::random(&mut rng)))
758    }
759
760    pub fn random_less_than(mut rng: impl RngCore + CryptoRng, upper: U256) -> Self {
761        let upper = NonZero::new(upper).expect("upper bound must be non-zero");
762        PeerId(NonZero::<U256>::from_uint(U256::random_mod(
763            &mut rng, &upper,
764        )))
765    }
766}
767
768#[test]
769fn test_parse_peer_id() {
770    let peer_id = PeerId::random(vsss_rs::elliptic_curve::rand_core::OsRng);
771    let u256: ethers::types::U256 = peer_id.into();
772    let peer_id2 = u256.try_into().unwrap();
773    assert_eq!(peer_id, peer_id2);
774}
775
776#[test]
777fn test_into_scalar_pallas() {
778    use rand_core::SeedableRng;
779
780    let rng = rand_chacha::ChaChaRng::seed_from_u64(0);
781    let peer_id = PeerId::random(rng);
782    let id: pallas::Scalar = peer_id.into();
783    let limbs = id.to_raw();
784    assert_eq!(
785        limbs,
786        [
787            0x3fd0ff79135bb946,
788            0xcacf6941e56db2e4,
789            0xa49547659cb1baa7,
790            0x04e7181b6f5533de,
791        ]
792    );
793}