use secp256k1::ecdsa::RecoverableSignature;
use secp256k1::ecdsa::RecoveryId;
use secp256k1::Message;
use secp256k1::PublicKey;
use secp256k1::SecretKey;
use secp256k1::SECP256K1;
use sha2::Digest;
use sha2::Sha256;
use std::error::Error;
use tofuri_core::*;
#[cfg(feature = "vrf")]
use vrf::openssl::CipherSuite;
#[cfg(feature = "vrf")]
use vrf::openssl::ECVRF;
#[cfg(feature = "vrf")]
use vrf::VRF;
#[derive(Debug, Clone, Copy)]
pub struct Key {
pub secret_key: SecretKey,
}
impl Key {
pub fn generate() -> Key {
Key {
secret_key: SecretKey::new(&mut rand::thread_rng()),
}
}
pub fn from_slice(secret_key_bytes: &SecretKeyBytes) -> Result<Key, Box<dyn Error>> {
Ok(Key {
secret_key: SecretKey::from_slice(secret_key_bytes)?,
})
}
pub fn secret_key_bytes(&self) -> SecretKeyBytes {
self.secret_key.secret_bytes()
}
pub fn public_key(&self) -> PublicKey {
self.secret_key.public_key(SECP256K1)
}
pub fn public_key_bytes(&self) -> PublicKeyBytes {
self.public_key().serialize()
}
pub fn address_bytes(&self) -> AddressBytes {
Key::address(&self.public_key_bytes())
}
pub fn address(public_key_bytes: &PublicKeyBytes) -> AddressBytes {
let mut hasher = Sha256::new();
hasher.update(public_key_bytes);
let hash = hasher.finalize();
let mut address = [0; 20];
address.copy_from_slice(&hash[..20]);
address
}
pub fn sign(&self, hash: &Hash) -> Result<SignatureBytes, Box<dyn Error>> {
let message = Message::from_slice(hash)?;
Ok(loop {
let signature = SECP256K1.sign_ecdsa_recoverable_with_noncedata(&message, &self.secret_key, &rand::random());
let (recovery_id, signature_bytes) = signature.serialize_compact();
if recovery_id.to_i32() == RECOVERY_ID {
break signature_bytes;
}
})
}
pub fn recover(hash: &Hash, signature_bytes: &SignatureBytes) -> Result<PublicKeyBytes, Box<dyn Error>> {
let message = Message::from_slice(hash)?;
let signature = RecoverableSignature::from_compact(signature_bytes, RecoveryId::from_i32(RECOVERY_ID).unwrap())?;
let public_key_bytes: PublicKeyBytes = SECP256K1.recover_ecdsa(&message, &signature)?.serialize();
Ok(public_key_bytes)
}
pub fn subkey(&self, n: u128) -> Result<Key, Box<dyn Error>> {
let mut hasher = Sha256::new();
hasher.update(self.secret_key_bytes());
hasher.update(n.to_be_bytes());
Key::from_slice(&hasher.finalize().into())
}
#[cfg(feature = "vrf")]
pub fn vrf_prove(&self, alpha: &[u8]) -> Option<Pi> {
let mut vrf = ECVRF::from_suite(CipherSuite::SECP256K1_SHA256_TAI).unwrap();
let pi = vrf.prove(&self.secret_key_bytes(), alpha);
if pi.is_err() {
return None;
}
Some(pi.unwrap().try_into().unwrap())
}
#[cfg(feature = "vrf")]
pub fn vrf_proof_to_hash(pi: &[u8]) -> Option<Beta> {
let mut vrf = ECVRF::from_suite(CipherSuite::SECP256K1_SHA256_TAI).unwrap();
let beta = vrf.proof_to_hash(pi);
if beta.is_err() {
return None;
}
Some(beta.unwrap().try_into().unwrap())
}
#[cfg(feature = "vrf")]
pub fn vrf_verify(y: &[u8], pi: &[u8], alpha: &[u8]) -> Option<Beta> {
let mut vrf = ECVRF::from_suite(CipherSuite::SECP256K1_SHA256_TAI).unwrap();
let beta = vrf.verify(y, pi, alpha);
if beta.is_err() {
return None;
}
Some(beta.unwrap().try_into().unwrap())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_address() {
assert_eq!(
Key::address(&[0; 33]),
[0x7f, 0x9c, 0x9e, 0x31, 0xac, 0x82, 0x56, 0xca, 0x2f, 0x25, 0x85, 0x83, 0xdf, 0x26, 0x2d, 0xbc, 0x7d, 0x6f, 0x68, 0xf2]
);
}
#[test]
fn test_sign_verify() {
let key = Key::generate();
let hash = [0; 32];
let signature_bytes = key.sign(&hash).unwrap();
assert_eq!(key.public_key_bytes(), Key::recover(&hash, &signature_bytes).unwrap());
}
#[test]
#[cfg(feature = "vrf")]
fn test_vrf_public_key() {
let mut vrf = ECVRF::from_suite(CipherSuite::SECP256K1_SHA256_TAI).unwrap();
let key = Key::generate();
let public_key = vrf.derive_public_key(&key.secret_key_bytes()).unwrap();
assert_eq!(key.public_key_bytes().to_vec(), public_key);
}
#[test]
#[cfg(feature = "vrf")]
fn test_vrf_prove_verify() {
let key = Key::generate();
let alpha: [u8; 32] = rand::random();
let pi = key.vrf_prove(&alpha).unwrap();
let beta = Key::vrf_verify(&key.public_key_bytes(), &pi, &alpha);
assert!(beta.unwrap() == Key::vrf_proof_to_hash(&pi).unwrap());
}
#[test]
fn test_subkey() {
let key = Key::from_slice(&[0xcd; 32]).unwrap();
let subkey = key.subkey(0).unwrap();
assert_eq!(
subkey.secret_key_bytes(),
[
0xa2, 0xcf, 0x3f, 0x85, 0xbd, 0x37, 0xfa, 0x8d, 0x0a, 0xdc, 0xce, 0x6d, 0xde, 0x50, 0x2b, 0xa7, 0xe1, 0xc4, 0x75, 0x42, 0x35, 0x94, 0x81, 0xd0,
0x34, 0x4d, 0x35, 0xdd, 0x91, 0x94, 0xba, 0x63
]
);
}
}