/* This file is part of DarkFi (https://dark.fi)
*
* Copyright (C) 2020-2022 Dyne.org foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
use std::{
convert::TryFrom,
hash::{Hash, Hasher},
str::FromStr,
};
use darkfi_sdk::crypto::constants::NullifierK;
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::RngCore;
use crate::{
crypto::{address::Address, util::mod_r_p},
Error, Result,
};
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Keypair {
pub secret: SecretKey,
pub public: PublicKey,
}
impl Keypair {
pub fn new(secret: SecretKey) -> Self {
let public = PublicKey::from_secret(secret);
Self { secret, public }
}
pub fn random(mut rng: impl RngCore) -> Self {
let secret = SecretKey::random(&mut rng);
Self::new(secret)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, SerialDecodable, SerialEncodable)]
pub struct SecretKey(pub pallas::Base);
impl SecretKey {
pub fn random(mut rng: impl RngCore) -> Self {
let x = pallas::Base::random(&mut rng);
Self(x)
}
pub fn to_bytes(self) -> [u8; 32] {
self.0.to_repr()
}
pub fn from_bytes(bytes: [u8; 32]) -> Result {
match pallas::Base::from_repr(bytes).into() {
Some(k) => Ok(Self(k)),
None => Err(Error::SecretKeyFromBytes),
}
}
pub fn inner(&self) -> pallas::Base {
self.0
}
}
impl From for SecretKey {
fn from(x: pallas::Base) -> Self {
Self(x)
}
}
impl FromStr for SecretKey {
type Err = crate::Error;
/// Tries to create a `SecretKey` instance from a base58 encoded string.
fn from_str(encoded: &str) -> core::result::Result {
let decoded = bs58::decode(encoded).into_vec()?;
if decoded.len() != 32 {
return Err(Error::SecretKeyFromStr)
}
Self::from_bytes(decoded.try_into().unwrap())
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, SerialDecodable, SerialEncodable)]
pub struct PublicKey(pub pallas::Point);
impl PublicKey {
pub fn random(mut rng: impl RngCore) -> Self {
let p = pallas::Point::random(&mut rng);
Self(p)
}
pub fn from_secret(s: SecretKey) -> Self {
let nfk = NullifierK;
let p = nfk.generator() * mod_r_p(s.0);
Self(p)
}
pub fn to_bytes(self) -> [u8; 32] {
self.0.to_bytes()
}
pub fn from_bytes(bytes: &[u8; 32]) -> Result {
match pallas::Point::from_bytes(bytes).into() {
Some(k) => Ok(Self(k)),
None => Err(Error::PublicKeyFromBytes),
}
}
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 Hash for PublicKey {
fn hash(&self, state: &mut H) {
let bytes = self.0.to_affine().to_bytes();
bytes.hash(state);
}
}
impl FromStr for PublicKey {
type Err = crate::Error;
/// Tries to create a `PublicKey` instance from a base58 encoded string.
fn from_str(encoded: &str) -> core::result::Result {
let decoded = bs58::decode(encoded).into_vec()?;
if decoded.len() != 32 {
return Err(Error::PublicKeyFromStr)
}
Self::from_bytes(&decoded.try_into().unwrap())
}
}
impl From for PublicKey {
fn from(x: pallas::Point) -> Self {
Self(x)
}
}
impl TryFrom for PublicKey {
type Error = Error;
fn try_from(address: Address) -> Result {
let mut bytes = [0u8; 32];
bytes.copy_from_slice(&address.0[1..33]);
Self::from_bytes(&bytes)
}
}