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;
23use darkfi_serial::{SerialDecodable, SerialEncodable};
24use halo2_gadgets::ecc::chip::FixedPoint;
25use pasta_curves::{
26 arithmetic::CurveAffine,
27 group::{
28 ff::{Field, PrimeField},
29 Curve, Group, GroupEncoding,
30 },
31 pallas,
32};
33use rand_core::{CryptoRng, RngCore};
3435use super::{constants::NullifierK, util::fp_mod_fv};
36use crate::error::ContractError;
3738/// Keypair structure holding a `SecretKey` and its respective `PublicKey`
39#[derive(Copy, Clone, PartialEq, Eq, Debug, SerialEncodable, SerialDecodable)]
40pub struct Keypair {
41pub secret: SecretKey,
42pub public: PublicKey,
43}
4445impl Keypair {
46/// Instantiate a new `Keypair` given a `SecretKey`
47pub fn new(secret: SecretKey) -> Self {
48Self { secret, public: PublicKey::from_secret(secret) }
49 }
5051/// Generate a new `Keypair` object given a source of randomness
52pub fn random(rng: &mut (impl CryptoRng + RngCore)) -> Self {
53Self::new(SecretKey::random(rng))
54 }
55}
5657impl Default for Keypair {
58/// Default Keypair used in genesis block generation
59fn default() -> Self {
60let secret = SecretKey::from(pallas::Base::from(42));
61let public = PublicKey::from_secret(secret);
62Self { secret, public }
63 }
64}
6566/// Structure holding a secret key, wrapping a `pallas::Base` element.
67#[derive(Copy, Clone, PartialEq, Eq, Debug, SerialEncodable, SerialDecodable)]
68pub struct SecretKey(pallas::Base);
6970impl SecretKey {
71/// Get the inner object wrapped by `SecretKey`
72pub fn inner(&self) -> pallas::Base {
73self.0
74}
7576/// Generate a new `SecretKey` given a source of randomness
77pub fn random(rng: &mut (impl CryptoRng + RngCore)) -> Self {
78Self(pallas::Base::random(rng))
79 }
8081/// Instantiate a `SecretKey` given 32 bytes. Returns an error
82 /// if the representation is noncanonical.
83pub fn from_bytes(bytes: [u8; 32]) -> Result<Self, ContractError> {
84match pallas::Base::from_repr(bytes).into() {
85Some(k) => Ok(Self(k)),
86None => Err(ContractError::IoError("Could not convert bytes to SecretKey".to_string())),
87 }
88 }
89}
9091impl From<pallas::Base> for SecretKey {
92fn from(x: pallas::Base) -> Self {
93Self(x)
94 }
95}
9697impl FromStr for SecretKey {
98type Err = ContractError;
99100/// Tries to create a `SecretKey` object from a base58 encoded string.
101fn from_str(enc: &str) -> Result<Self, Self::Err> {
102let decoded = bs58::decode(enc).into_vec()?;
103if decoded.len() != 32 {
104return Err(Self::Err::IoError(
105"Failed decoding SecretKey from bytes, len is not 32".to_string(),
106 ))
107 }
108109Self::from_bytes(decoded.try_into().unwrap())
110 }
111}
112113impl core::fmt::Display for SecretKey {
114fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
115let disp: String = bs58::encode(self.0.to_repr()).into_string();
116write!(f, "{}", disp)
117 }
118}
119120/// Structure holding a public key, wrapping a `pallas::Point` element.
121#[derive(Copy, Clone, PartialEq, Eq, Debug, SerialEncodable, SerialDecodable)]
122pub struct PublicKey(pallas::Point);
123124impl PublicKey {
125/// Get the inner object wrapped by `PublicKey`
126pub fn inner(&self) -> pallas::Point {
127self.0
128}
129130/// Derive a new `PublicKey` object given a `SecretKey`
131pub fn from_secret(s: SecretKey) -> Self {
132let p = NullifierK.generator() * fp_mod_fv(s.inner());
133Self(p)
134 }
135136/// Instantiate a `PublicKey` given 32 bytes. Returns an error
137 /// if the representation is noncanonical.
138pub fn from_bytes(bytes: [u8; 32]) -> Result<Self, ContractError> {
139match <subtle::CtOption<pallas::Point> as Into<Option<pallas::Point>>>::into(
140 pallas::Point::from_bytes(&bytes),
141 ) {
142Some(k) => {
143if bool::from(k.is_identity()) {
144return Err(ContractError::IoError(
145"Could not convert bytes to PublicKey".to_string(),
146 ))
147 }
148149Ok(Self(k))
150 }
151None => Err(ContractError::IoError("Could not convert bytes to PublicKey".to_string())),
152 }
153 }
154155/// Downcast the `PublicKey` to 32 bytes of `pallas::Point`
156pub fn to_bytes(&self) -> [u8; 32] {
157self.0.to_bytes()
158 }
159160/// Fetch the `x` coordinate of this `PublicKey`
161pub fn x(&self) -> pallas::Base {
162*self.0.to_affine().coordinates().unwrap().x()
163 }
164165/// Fetch the `y` coordinate of this `PublicKey`
166pub fn y(&self) -> pallas::Base {
167*self.0.to_affine().coordinates().unwrap().y()
168 }
169170/// Fetch the `x` and `y` coordinates of this `PublicKey` as a tuple
171pub fn xy(&self) -> (pallas::Base, pallas::Base) {
172let coords = self.0.to_affine().coordinates().unwrap();
173 (*coords.x(), *coords.y())
174 }
175}
176177impl TryFrom<pallas::Point> for PublicKey {
178type Error = ContractError;
179180fn try_from(x: pallas::Point) -> Result<Self, Self::Error> {
181if bool::from(x.is_identity()) {
182return Err(ContractError::IoError(
183"Could not convert identity point to PublicKey".to_string(),
184 ))
185 }
186187Ok(Self(x))
188 }
189}
190191impl FromStr for PublicKey {
192type Err = ContractError;
193194/// Tries to create a `PublicKey` object from a base58 encoded string.
195fn from_str(enc: &str) -> Result<Self, Self::Err> {
196let decoded = bs58::decode(enc).into_vec()?;
197if decoded.len() != 32 {
198return Err(Self::Err::IoError(
199"Failed decoding PublicKey from bytes, len is not 32".to_string(),
200 ))
201 }
202203Self::from_bytes(decoded.try_into().unwrap())
204 }
205}
206207impl core::fmt::Display for PublicKey {
208fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
209let disp: String = bs58::encode(self.0.to_bytes()).into_string();
210write!(f, "{}", disp)
211 }
212}