use curve25519_dalek::constants;
use curve25519_dalek::ristretto::{CompressedRistretto};
use curve25519_dalek::scalar::Scalar;
use super::*;
use crate::context::SigningTranscript;
#[derive(Clone, Copy)] pub struct AdaptorCertSecret(pub [u8; 64]);
impl From<AdaptorCertSecret> for AdaptorCertPublic {
fn from(secret: AdaptorCertSecret) -> AdaptorCertPublic {
let mut public = AdaptorCertPublic([0u8; 32]);
public.0.copy_from_slice(&secret.0[0..32]);
public
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct AdaptorCertPublic(pub [u8; 32]);
impl AdaptorCertPublic {
fn derive_e<T: SigningTranscript>(&self, mut t: T) -> Scalar {
t.challenge_scalar(b"adaptor-e")
}
}
impl Keypair {
pub fn issue_adaptor_cert<T>(&self, mut t: T, seed_public_key: &PublicKey) -> AdaptorCertSecret
where
T: SigningTranscript,
{
t.proto_name(b"Adaptor");
t.commit_point(b"issuer-pk", self.public.as_compressed());
let k = t.witness_scalar(
b"issuing",
&[&self.secret.nonce, seed_public_key.as_compressed().as_bytes()],
);
let gamma = seed_public_key.as_point() + &k * constants::RISTRETTO_BASEPOINT_TABLE;
let gamma = gamma.compress();
t.commit_point(b"gamma", &gamma);
let cert_public = AdaptorCertPublic(gamma.0);
let s = k + cert_public.derive_e(t) * self.secret.key;
let mut cert_secret = AdaptorCertSecret([0u8; 64]);
cert_secret.0[0..32].copy_from_slice(&cert_public.0[..]);
cert_secret.0[32..64].copy_from_slice(s.as_bytes());
cert_secret
}
}
impl PublicKey {
pub fn accept_adaptor_cert<T>(
&self,
mut t: T,
seed_secret_key: &SecretKey,
cert_secret: AdaptorCertSecret,
) -> SignatureResult<(AdaptorCertPublic, SecretKey)>
where
T: SigningTranscript,
{
t.proto_name(b"Adaptor");
t.commit_point(b"issuer-pk", self.as_compressed());
let mut nonce = [0u8; 32];
t.witness_bytes(b"accepting", &mut nonce, &[&cert_secret.0[..], &seed_secret_key.nonce]);
let mut s = [0u8; 32];
s.copy_from_slice(&cert_secret.0[32..64]);
let s = crate::scalar_from_canonical_bytes(s).ok_or(SignatureError::ScalarFormatError)?;
let cert_public: AdaptorCertPublic = cert_secret.into();
let gamma = CompressedRistretto(cert_public.0);
t.commit_point(b"gamma", &gamma);
let key = s + seed_secret_key.key;
Ok((cert_public, SecretKey { key, nonce }))
}
}
impl Keypair {
pub fn issue_self_adaptor_cert<T>(&self, t: T) -> (AdaptorCertPublic, SecretKey)
where
T: SigningTranscript + Clone,
{
let mut bytes = [0u8; 96];
t.witness_bytes(
b"issue_self_adaptor_cert",
&mut bytes,
&[&self.secret.nonce, &self.secret.to_bytes() as &[u8]],
);
let mut nonce = [0u8; 32];
nonce.copy_from_slice(&bytes[64..96]);
let mut key = [0u8; 64];
key.copy_from_slice(&bytes[0..64]);
let key = Scalar::from_bytes_mod_order_wide(&key);
let seed = SecretKey { key, nonce }.to_keypair();
let cert_secret = self.issue_adaptor_cert(t.clone(), &seed.public);
self.public
.accept_adaptor_cert(t, &seed.secret, cert_secret)
.expect("Cert issued above and known to produce signature errors; qed")
}
}
impl PublicKey {
pub fn open_adaptor_cert<T>(
&self,
mut t: T,
cert_public: &AdaptorCertPublic,
) -> SignatureResult<PublicKey>
where
T: SigningTranscript,
{
t.proto_name(b"Adaptor");
t.commit_point(b"issuer-pk", self.as_compressed());
let gamma = CompressedRistretto(cert_public.0);
t.commit_point(b"gamma", &gamma);
let gamma = gamma.decompress().ok_or(SignatureError::PointDecompressionError)?;
let point = cert_public.derive_e(t) * self.as_point() + gamma;
Ok(PublicKey::from_point(point))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "getrandom")]
#[test]
fn adaptor_cert_public_vs_private_paths() {
let t = signing_context(b"").bytes(b"MrMeow!");
let mut csprng = rand_core::OsRng;
let issuer = Keypair::generate_with(&mut csprng);
let (cert_public, secret_key) = issuer.issue_self_adaptor_cert(t.clone());
let public_key = issuer.public.open_adaptor_cert(t, &cert_public).unwrap();
assert_eq!(secret_key.to_public(), public_key);
}
}