ecdsa_fun 0.12.0

Bitcoin compatible ECDSA signatures based on secp256kfun
Documentation
#![cfg(all(feature = "serde", feature = "alloc", feature = "adaptor"))]

static DLC_SPEC_JSON: &str = include_str!("./test_vectors.json");
use ecdsa_fun::{
    Signature,
    adaptor::{Adaptor, EncryptedSignature, HashTranscript},
    fun::{Point, Scalar, serde},
    nonce::NoNonces,
};
use sha2::Sha256;

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(tag = "kind", rename_all = "snake_case", crate = "self::serde")]
enum TestVector {
    Verification(Verification),
    Recovery(Recovery),
    Serialization(Serialization),
}

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(crate = "self::serde")]
struct Recovery {
    encryption_key: Point,
    signature: Signature,
    adaptor_sig: EncryptedSignature,
    decryption_key: Option<Scalar>,
}

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(crate = "self::serde")]
struct Verification {
    adaptor_sig: EncryptedSignature,
    public_signing_key: Point,
    encryption_key: Point,
    signature: Signature,
    decryption_key: Scalar,
    message_hash: Scalar,
    error: Option<String>,
}

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(crate = "self::serde")]
struct Serialization {
    adaptor_sig: String,
    error: Option<String>,
}

#[test]
fn run_ecdsa_adaptor_test_vectors() {
    let ecdsa_adaptor = Adaptor::<HashTranscript<Sha256>, _>::verify_only();
    let test_vectors = serde_json::from_str::<Vec<TestVector>>(DLC_SPEC_JSON).unwrap();
    for t in test_vectors {
        match t {
            TestVector::Verification(t) => {
                if run_test_vector(&ecdsa_adaptor, &t) {
                    assert_eq!(t.error, None)
                } else {
                    assert!(t.error.is_some())
                }
            }
            TestVector::Recovery(t) => {
                let decryption_key = ecdsa_adaptor.recover_decryption_key(
                    &t.encryption_key,
                    &t.signature,
                    &t.adaptor_sig,
                );
                assert_eq!(decryption_key, t.decryption_key);
            }
            TestVector::Serialization(t) => {
                use core::str::FromStr;
                match EncryptedSignature::from_str(&t.adaptor_sig) {
                    Ok(encrypted_sig) => {
                        assert!(t.error.is_none());
                        assert_eq!(encrypted_sig.to_string(), t.adaptor_sig);
                    }
                    Err(_) => assert!(t.error.is_some()),
                }
            }
        }
    }
}

fn run_test_vector(
    ecdsa_adaptor: &Adaptor<HashTranscript<Sha256>, NoNonces>,
    t: &Verification,
) -> bool {
    if !ecdsa_adaptor.verify_encrypted_signature(
        &t.public_signing_key,
        &t.encryption_key,
        &t.message_hash.to_bytes(),
        &t.adaptor_sig,
    ) {
        return false;
    }

    let signature = ecdsa_adaptor.decrypt_signature(&t.decryption_key, t.adaptor_sig.clone());

    if t.signature != signature {
        return false;
    }

    let decryption_key =
        ecdsa_adaptor.recover_decryption_key(&t.encryption_key, &t.signature, &t.adaptor_sig);

    decryption_key == Some(t.decryption_key)
}