use std::io; use halo2_gadgets::ecc::FixedPoints; use pasta_curves::{arithmetic::Field, group::GroupEncoding}; use rand::rngs::OsRng; use super::{ constants::{OrchardFixedBases, DRK_SCHNORR_DOMAIN}, types::*, util::{hash_to_scalar, mod_r_p}, }; use crate::error::Result; use crate::serial::{Decodable, Encodable}; pub struct SecretKey(pub DrkSecretKey); impl SecretKey { pub fn random() -> Self { Self(DrkSecretKey::random(&mut OsRng)) } pub fn sign(&self, message: &[u8]) -> Signature { let mask = DrkValueBlind::random(&mut OsRng); let commit = OrchardFixedBases::SpendAuthG.generator() * mask; let challenge = hash_to_scalar(DRK_SCHNORR_DOMAIN, &commit.to_bytes(), message); let response = mask + challenge * mod_r_p(self.0); Signature { commit, response } } pub fn public_key(&self) -> PublicKey { PublicKey(derive_publickey(self.0)) } } pub struct PublicKey(pub DrkPublicKey); pub struct Signature { commit: DrkValueCommit, response: DrkValueBlind, } impl Encodable for Signature { fn encode(&self, mut s: S) -> Result { let mut len = 0; len += self.commit.encode(&mut s)?; len += self.response.encode(s)?; Ok(len) } } impl Decodable for Signature { fn decode(mut d: D) -> Result { Ok(Self { commit: Decodable::decode(&mut d)?, response: Decodable::decode(d)?, }) } } impl PublicKey { pub fn verify(&self, message: &[u8], signature: &Signature) -> bool { let challenge = hash_to_scalar(DRK_SCHNORR_DOMAIN, &signature.commit.to_bytes(), message); OrchardFixedBases::SpendAuthG.generator() * signature.response - self.0 * challenge == signature.commit } } #[test] fn test_schnorr() { let secret = SecretKey::random(); let message = b"Foo bar"; let signature = secret.sign(&message[..]); let public = secret.public_key(); assert!(public.verify(&message[..], &signature)); }