#![forbid(unsafe_code)]
use snarkvm::{
console::{network::prelude::*, types::Field},
prelude::*,
};
use colored::*;
use core::fmt;
#[derive(Clone, Debug)]
pub struct Account<N: Network> {
private_key: PrivateKey<N>,
view_key: ViewKey<N>,
address: Address<N>,
}
impl<N: Network> Account<N> {
pub fn new<R: Rng + CryptoRng>(rng: &mut R) -> Result<Self> {
Self::try_from(PrivateKey::new(rng)?)
}
pub const fn private_key(&self) -> &PrivateKey<N> {
&self.private_key
}
pub const fn view_key(&self) -> &ViewKey<N> {
&self.view_key
}
pub const fn address(&self) -> Address<N> {
self.address
}
}
impl<N: Network> Account<N> {
pub fn sign<R: Rng + CryptoRng>(&self, message: &[Field<N>], rng: &mut R) -> Result<Signature<N>> {
Signature::sign(&self.private_key, message, rng)
}
pub fn sign_bytes<R: Rng + CryptoRng>(&self, message: &[u8], rng: &mut R) -> Result<Signature<N>> {
Signature::sign_bytes(&self.private_key, message, rng)
}
pub fn sign_bits<R: Rng + CryptoRng>(&self, message: &[bool], rng: &mut R) -> Result<Signature<N>> {
Signature::sign_bits(&self.private_key, message, rng)
}
pub fn verify(&self, message: &[Field<N>], signature: &Signature<N>) -> bool {
signature.verify(&self.address, message)
}
pub fn verify_bytes(&self, message: &[u8], signature: &Signature<N>) -> bool {
signature.verify_bytes(&self.address, message)
}
pub fn verify_bits(&self, message: &[bool], signature: &Signature<N>) -> bool {
signature.verify_bits(&self.address, message)
}
}
impl<N: Network> TryFrom<PrivateKey<N>> for Account<N> {
type Error = Error;
fn try_from(private_key: PrivateKey<N>) -> Result<Self, Self::Error> {
Self::try_from(&private_key)
}
}
impl<N: Network> TryFrom<&PrivateKey<N>> for Account<N> {
type Error = Error;
fn try_from(private_key: &PrivateKey<N>) -> Result<Self, Self::Error> {
let view_key = ViewKey::try_from(private_key)?;
let address = view_key.to_address();
Ok(Self { private_key: *private_key, view_key, address })
}
}
impl<N: Network> TryFrom<String> for Account<N> {
type Error = Error;
fn try_from(private_key: String) -> Result<Self, Self::Error> {
Self::try_from(&private_key)
}
}
impl<N: Network> TryFrom<&String> for Account<N> {
type Error = Error;
fn try_from(private_key: &String) -> Result<Self, Self::Error> {
Self::from_str(private_key.as_str())
}
}
impl<N: Network> TryFrom<&str> for Account<N> {
type Error = Error;
fn try_from(private_key: &str) -> Result<Self, Self::Error> {
Self::from_str(private_key)
}
}
impl<N: Network> FromStr for Account<N> {
type Err = Error;
fn from_str(private_key: &str) -> Result<Self, Self::Err> {
Self::try_from(PrivateKey::from_str(private_key)?)
}
}
impl<N: Network> Display for Account<N> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
" {:>12} {}\n {:>12} {}\n {:>12} {}",
"Private Key".cyan().bold(),
self.private_key,
"View Key".cyan().bold(),
self.view_key,
"Address".cyan().bold(),
self.address
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use snarkvm::prelude::Testnet3;
type CurrentNetwork = Testnet3;
#[test]
fn test_sign() {
let mut rng = TestRng::default();
let account = Account::<CurrentNetwork>::new(&mut rng).unwrap();
let message = vec![Field::rand(&mut rng); 10];
let signature = account.sign(&message, &mut rng).unwrap();
assert!(account.verify(&message, &signature));
}
#[test]
fn test_sign_bytes() {
let mut rng = TestRng::default();
let account = Account::<CurrentNetwork>::new(&mut rng).unwrap();
let message = (0..10).map(|_| rng.gen::<u8>()).collect::<Vec<u8>>();
let signature = account.sign_bytes(&message, &mut rng).unwrap();
assert!(account.verify_bytes(&message, &signature));
}
#[test]
fn test_sign_bits() {
let mut rng = TestRng::default();
let account = Account::<CurrentNetwork>::new(&mut rng).unwrap();
let message = (0..10).map(|_| rng.gen::<bool>()).collect::<Vec<bool>>();
let signature = account.sign_bits(&message, &mut rng).unwrap();
assert!(account.verify_bits(&message, &signature));
}
}