ergotree_interpreter/sigma_protocol/
wscalar.rs1use 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)]
30pub struct Wscalar(Scalar);
32
33impl Wscalar {
34 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 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}