darkfi_sdk/crypto/
keypair.rs1use core::str::FromStr;
20
21#[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};
34
35use super::{constants::NullifierK, util::fp_mod_fv};
36use crate::error::ContractError;
37
38#[derive(Copy, Clone, PartialEq, Eq, Debug, SerialEncodable, SerialDecodable)]
40pub struct Keypair {
41 pub secret: SecretKey,
42 pub public: PublicKey,
43}
44
45impl Keypair {
46 pub fn new(secret: SecretKey) -> Self {
48 Self { secret, public: PublicKey::from_secret(secret) }
49 }
50
51 pub fn random(rng: &mut (impl CryptoRng + RngCore)) -> Self {
53 Self::new(SecretKey::random(rng))
54 }
55}
56
57impl Default for Keypair {
58 fn default() -> Self {
60 let secret = SecretKey::from(pallas::Base::from(42));
61 let public = PublicKey::from_secret(secret);
62 Self { secret, public }
63 }
64}
65
66#[derive(Copy, Clone, PartialEq, Eq, Debug, SerialEncodable, SerialDecodable)]
68pub struct SecretKey(pallas::Base);
69
70impl SecretKey {
71 pub fn inner(&self) -> pallas::Base {
73 self.0
74 }
75
76 pub fn random(rng: &mut (impl CryptoRng + RngCore)) -> Self {
78 Self(pallas::Base::random(rng))
79 }
80
81 pub fn from_bytes(bytes: [u8; 32]) -> Result<Self, ContractError> {
84 match pallas::Base::from_repr(bytes).into() {
85 Some(k) => Ok(Self(k)),
86 None => Err(ContractError::IoError("Could not convert bytes to SecretKey".to_string())),
87 }
88 }
89}
90
91impl From<pallas::Base> for SecretKey {
92 fn from(x: pallas::Base) -> Self {
93 Self(x)
94 }
95}
96
97impl FromStr for SecretKey {
98 type Err = ContractError;
99
100 fn from_str(enc: &str) -> Result<Self, Self::Err> {
102 let decoded = bs58::decode(enc).into_vec()?;
103 if decoded.len() != 32 {
104 return Err(Self::Err::IoError(
105 "Failed decoding SecretKey from bytes, len is not 32".to_string(),
106 ))
107 }
108
109 Self::from_bytes(decoded.try_into().unwrap())
110 }
111}
112
113impl core::fmt::Display for SecretKey {
114 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
115 let disp: String = bs58::encode(self.0.to_repr()).into_string();
116 write!(f, "{disp}")
117 }
118}
119
120#[derive(Copy, Clone, PartialEq, Eq, Debug, SerialEncodable, SerialDecodable)]
122pub struct PublicKey(pallas::Point);
123
124impl PublicKey {
125 pub fn inner(&self) -> pallas::Point {
127 self.0
128 }
129
130 pub fn from_secret(s: SecretKey) -> Self {
132 let p = NullifierK.generator() * fp_mod_fv(s.inner());
133 Self(p)
134 }
135
136 pub fn from_bytes(bytes: [u8; 32]) -> Result<Self, ContractError> {
139 match <subtle::CtOption<pallas::Point> as Into<Option<pallas::Point>>>::into(
140 pallas::Point::from_bytes(&bytes),
141 ) {
142 Some(k) => {
143 if bool::from(k.is_identity()) {
144 return Err(ContractError::IoError(
145 "Could not convert bytes to PublicKey".to_string(),
146 ))
147 }
148
149 Ok(Self(k))
150 }
151 None => Err(ContractError::IoError("Could not convert bytes to PublicKey".to_string())),
152 }
153 }
154
155 pub fn to_bytes(&self) -> [u8; 32] {
157 self.0.to_bytes()
158 }
159
160 pub fn x(&self) -> pallas::Base {
162 *self.0.to_affine().coordinates().unwrap().x()
163 }
164
165 pub fn y(&self) -> pallas::Base {
167 *self.0.to_affine().coordinates().unwrap().y()
168 }
169
170 pub fn xy(&self) -> (pallas::Base, pallas::Base) {
172 let coords = self.0.to_affine().coordinates().unwrap();
173 (*coords.x(), *coords.y())
174 }
175}
176
177impl TryFrom<pallas::Point> for PublicKey {
178 type Error = ContractError;
179
180 fn try_from(x: pallas::Point) -> Result<Self, Self::Error> {
181 if bool::from(x.is_identity()) {
182 return Err(ContractError::IoError(
183 "Could not convert identity point to PublicKey".to_string(),
184 ))
185 }
186
187 Ok(Self(x))
188 }
189}
190
191impl FromStr for PublicKey {
192 type Err = ContractError;
193
194 fn from_str(enc: &str) -> Result<Self, Self::Err> {
196 let decoded = bs58::decode(enc).into_vec()?;
197 if decoded.len() != 32 {
198 return Err(Self::Err::IoError(
199 "Failed decoding PublicKey from bytes, len is not 32".to_string(),
200 ))
201 }
202
203 Self::from_bytes(decoded.try_into().unwrap())
204 }
205}
206
207impl core::fmt::Display for PublicKey {
208 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
209 let disp: String = bs58::encode(self.0.to_bytes()).into_string();
210 write!(f, "{disp}")
211 }
212}