1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2025 Dyne.org foundation
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
1819use core::str::FromStr;
2021#[cfg(feature = "async")]
22use darkfi_serial::{async_trait, AsyncDecodable, AsyncEncodable};
23use darkfi_serial::{Decodable, Encodable, SerialDecodable, SerialEncodable};
2425use pasta_curves::{
26 group::ff::{Field, PrimeField},
27 pallas,
28};
29use rand_core::{CryptoRng, RngCore};
3031use crate::error::ContractError;
3233#[cfg(feature = "async")]
34pub trait EncDecode: Encodable + Decodable + AsyncEncodable + AsyncDecodable {}
35#[cfg(not(feature = "async"))]
36pub trait EncDecode: Encodable + Decodable {}
3738impl EncDecode for pallas::Base {}
39impl EncDecode for pallas::Scalar {}
4041/// Blinding factor used in bullas. Every bulla should contain one.
42#[derive(Debug, Copy, Clone, Eq, PartialEq, SerialEncodable, SerialDecodable)]
43pub struct Blind<F: Field + EncDecode>(pub F);
4445impl<F: Field + EncDecode> Blind<F> {
46pub const ZERO: Self = Self(F::ZERO);
4748pub fn random(rng: &mut (impl CryptoRng + RngCore)) -> Self {
49Self(F::random(rng))
50 }
5152pub fn inner(&self) -> F {
53self.0
54}
55}
5657impl<'a, F: Field + EncDecode> std::ops::Add<&'a Blind<F>> for &Blind<F> {
58type Output = Blind<F>;
5960#[inline]
61fn add(self, rhs: &'a Blind<F>) -> Blind<F> {
62 Blind(self.0.add(rhs.0))
63 }
64}
6566impl<F: Field + EncDecode> std::ops::AddAssign for Blind<F> {
67#[inline]
68fn add_assign(&mut self, other: Self) {
69self.0.add_assign(other.0)
70 }
71}
7273pub type BaseBlind = Blind<pallas::Base>;
74pub type ScalarBlind = Blind<pallas::Scalar>;
7576impl From<u64> for BaseBlind {
77fn from(x: u64) -> Self {
78Self(pallas::Base::from(x))
79 }
80}
8182impl FromStr for BaseBlind {
83type Err = ContractError;
8485/// Tries to create a `BaseBlind` object from a base58 encoded string.
86fn from_str(enc: &str) -> Result<Self, Self::Err> {
87let decoded = bs58::decode(enc).into_vec()?;
88if decoded.len() != 32 {
89return Err(Self::Err::IoError(
90"Failed decoding BaseBlind from bytes, len is not 32".to_string(),
91 ))
92 }
9394match pallas::Base::from_repr(decoded.try_into().unwrap()).into() {
95Some(k) => Ok(Self(k)),
96None => Err(ContractError::IoError("Could not convert bytes to BaseBlind".to_string())),
97 }
98 }
99}
100101impl core::fmt::Display for BaseBlind {
102fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
103let disp: String = bs58::encode(self.0.to_repr()).into_string();
104write!(f, "{}", disp)
105 }
106}
107108impl From<u64> for ScalarBlind {
109fn from(x: u64) -> Self {
110Self(pallas::Scalar::from(x))
111 }
112}
113114impl FromStr for ScalarBlind {
115type Err = ContractError;
116117/// Tries to create a `ScalarBlind` object from a base58 encoded string.
118fn from_str(enc: &str) -> Result<Self, Self::Err> {
119let decoded = bs58::decode(enc).into_vec()?;
120if decoded.len() != 32 {
121return Err(Self::Err::IoError(
122"Failed decoding ScalarBlind from bytes, len is not 32".to_string(),
123 ))
124 }
125126match pallas::Scalar::from_repr(decoded.try_into().unwrap()).into() {
127Some(k) => Ok(Self(k)),
128None => {
129Err(ContractError::IoError("Could not convert bytes to ScalarBlind".to_string()))
130 }
131 }
132 }
133}
134135impl core::fmt::Display for ScalarBlind {
136fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
137let disp: String = bs58::encode(self.0.to_repr()).into_string();
138write!(f, "{}", disp)
139 }
140}