use core::str::FromStr;
#[cfg(feature = "async")]
use darkfi_serial::async_trait;
use darkfi_serial::{SerialDecodable, SerialEncodable};
use halo2_gadgets::ecc::chip::FixedPoint;
use pasta_curves::{
arithmetic::CurveAffine,
group::{
ff::{Field, PrimeField},
Curve, Group, GroupEncoding,
},
pallas,
};
use rand_core::{CryptoRng, RngCore};
use super::{constants::NullifierK, util::fp_mod_fv};
use crate::error::ContractError;
#[derive(Copy, Clone, PartialEq, Eq, Debug, SerialEncodable, SerialDecodable)]
pub struct Keypair {
pub secret: SecretKey,
pub public: PublicKey,
}
impl Keypair {
pub fn new(secret: SecretKey) -> Self {
Self { secret, public: PublicKey::from_secret(secret) }
}
pub fn random(rng: &mut (impl CryptoRng + RngCore)) -> Self {
Self::new(SecretKey::random(rng))
}
}
impl Default for Keypair {
fn default() -> Self {
let secret = SecretKey::from(pallas::Base::from(42));
let public = PublicKey::from_secret(secret);
Self { secret, public }
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, SerialEncodable, SerialDecodable)]
pub struct SecretKey(pallas::Base);
impl SecretKey {
pub fn inner(&self) -> pallas::Base {
self.0
}
pub fn random(rng: &mut (impl CryptoRng + RngCore)) -> Self {
Self(pallas::Base::random(rng))
}
pub fn from_bytes(bytes: [u8; 32]) -> Result<Self, ContractError> {
match pallas::Base::from_repr(bytes).into() {
Some(k) => Ok(Self(k)),
None => Err(ContractError::IoError("Could not convert bytes to SecretKey".to_string())),
}
}
}
impl From<pallas::Base> for SecretKey {
fn from(x: pallas::Base) -> Self {
Self(x)
}
}
impl FromStr for SecretKey {
type Err = ContractError;
fn from_str(enc: &str) -> Result<Self, Self::Err> {
let decoded = bs58::decode(enc).into_vec()?;
if decoded.len() != 32 {
return Err(Self::Err::IoError(
"Failed decoding SecretKey from bytes, len is not 32".to_string(),
))
}
Self::from_bytes(decoded.try_into().unwrap())
}
}
impl core::fmt::Display for SecretKey {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
let disp: String = bs58::encode(self.0.to_repr()).into_string();
write!(f, "{}", disp)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, SerialEncodable, SerialDecodable)]
pub struct PublicKey(pallas::Point);
impl PublicKey {
pub fn inner(&self) -> pallas::Point {
self.0
}
pub fn from_secret(s: SecretKey) -> Self {
let p = NullifierK.generator() * fp_mod_fv(s.inner());
Self(p)
}
pub fn from_bytes(bytes: [u8; 32]) -> Result<Self, ContractError> {
match <subtle::CtOption<pallas::Point> as Into<Option<pallas::Point>>>::into(
pallas::Point::from_bytes(&bytes),
) {
Some(k) => {
if bool::from(k.is_identity()) {
return Err(ContractError::IoError(
"Could not convert bytes to PublicKey".to_string(),
))
}
Ok(Self(k))
}
None => Err(ContractError::IoError("Could not convert bytes to PublicKey".to_string())),
}
}
pub fn to_bytes(&self) -> [u8; 32] {
self.0.to_bytes()
}
pub fn x(&self) -> pallas::Base {
*self.0.to_affine().coordinates().unwrap().x()
}
pub fn y(&self) -> pallas::Base {
*self.0.to_affine().coordinates().unwrap().y()
}
pub fn xy(&self) -> (pallas::Base, pallas::Base) {
let coords = self.0.to_affine().coordinates().unwrap();
(*coords.x(), *coords.y())
}
}
impl TryFrom<pallas::Point> for PublicKey {
type Error = ContractError;
fn try_from(x: pallas::Point) -> Result<Self, Self::Error> {
if bool::from(x.is_identity()) {
return Err(ContractError::IoError(
"Could not convert identity point to PublicKey".to_string(),
))
}
Ok(Self(x))
}
}
impl FromStr for PublicKey {
type Err = ContractError;
fn from_str(enc: &str) -> Result<Self, Self::Err> {
let decoded = bs58::decode(enc).into_vec()?;
if decoded.len() != 32 {
return Err(Self::Err::IoError(
"Failed decoding PublicKey from bytes, len is not 32".to_string(),
))
}
Self::from_bytes(decoded.try_into().unwrap())
}
}
impl core::fmt::Display for PublicKey {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
let disp: String = bs58::encode(self.0.to_bytes()).into_string();
write!(f, "{}", disp)
}
}