ergotree_interpreter/sigma_protocol/
wscalar.rs

1//! Wrapper for Scalar
2//! mainly for Arbitrary impl and JSON encoding
3
4use std::array::TryFromSliceError;
5use std::convert::TryFrom;
6use std::fmt::Formatter;
7
8use derive_more::From;
9use derive_more::Into;
10use ergo_chain_types::Base16DecodedBytes;
11use ergo_chain_types::Base16EncodedBytes;
12use k256::elliptic_curve::generic_array::GenericArray;
13use k256::elliptic_curve::ops::Reduce;
14use k256::Scalar;
15use k256::U256;
16
17use super::challenge::Challenge;
18use super::GroupSizedBytes;
19use super::SOUNDNESS_BYTES;
20
21#[derive(PartialEq, Eq, From, Into, Clone)]
22#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
23#[cfg_attr(
24    feature = "json",
25    serde(
26        try_from = "ergo_chain_types::Base16DecodedBytes",
27        into = "ergo_chain_types::Base16EncodedBytes"
28    )
29)]
30/// Wrapper for Scalar mainly for Arbitrary impl and JSON encoding
31pub struct Wscalar(Scalar);
32
33impl Wscalar {
34    /// Returns a reference to underlying Scalar
35    pub fn as_scalar_ref(&self) -> &Scalar {
36        &self.0
37    }
38}
39
40impl From<GroupSizedBytes> for Wscalar {
41    fn from(b: GroupSizedBytes) -> Self {
42        let sl: &[u8] = b.0.as_ref();
43        let s = <Scalar as Reduce<U256>>::reduce_bytes(&GenericArray::clone_from_slice(sl));
44        Wscalar(s)
45    }
46}
47
48impl From<Challenge> for Scalar {
49    fn from(v: Challenge) -> Self {
50        let v: [u8; SOUNDNESS_BYTES] = v.0.into();
51        // prepend zeroes to 32 bytes (big-endian)
52        let mut prefix = vec![0u8; 8];
53        prefix.append(&mut v.to_vec());
54        <Scalar as Reduce<U256>>::reduce_bytes(&GenericArray::clone_from_slice(&prefix))
55    }
56}
57
58impl From<Wscalar> for Base16EncodedBytes {
59    fn from(w: Wscalar) -> Self {
60        let bytes = w.0.to_bytes();
61        let bytes_ref: &[u8] = bytes.as_ref();
62        Base16EncodedBytes::new(bytes_ref)
63    }
64}
65
66impl TryFrom<Base16DecodedBytes> for Wscalar {
67    type Error = TryFromSliceError;
68
69    fn try_from(value: Base16DecodedBytes) -> Result<Self, Self::Error> {
70        let bytes = value.0;
71        GroupSizedBytes::try_from(bytes).map(Into::into)
72    }
73}
74
75impl std::fmt::Debug for Wscalar {
76    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
77        f.write_str("Wscalar:")?;
78        f.write_str(&base16::encode_lower(&(*self.0.to_bytes())))
79    }
80}
81
82#[cfg(feature = "arbitrary")]
83mod arbitrary {
84
85    use crate::sigma_protocol::GROUP_SIZE;
86
87    use super::Wscalar;
88    use k256::elliptic_curve::{generic_array::GenericArray, PrimeField};
89    use k256::Scalar;
90    use proptest::{collection::vec, prelude::*};
91
92    impl Arbitrary for Wscalar {
93        type Parameters = ();
94        type Strategy = BoxedStrategy<Self>;
95
96        fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
97            vec(any::<u8>(), GROUP_SIZE)
98                .prop_filter("must be in group range", |bytes| {
99                    let opt: Option<Scalar> =
100                        Scalar::from_repr(GenericArray::clone_from_slice(bytes)).into();
101                    opt.is_some()
102                })
103                .prop_map(|bytes| {
104                    Scalar::from_repr(GenericArray::clone_from_slice(&bytes))
105                        .unwrap()
106                        .into()
107                })
108                .boxed()
109        }
110    }
111}