use blake3::Hasher;
use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT;
use curve25519_dalek::ristretto::RistrettoPoint;
use curve25519_dalek::scalar::Scalar;
use rand::Rng as _;
use serde::{Deserialize, Serialize};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum AdaptorError {
#[error("Invalid public key")]
InvalidPublicKey,
#[error("Invalid signature")]
InvalidSignature,
#[error("Invalid adaptor point")]
InvalidAdaptorPoint,
#[error("Secret extraction failed")]
SecretExtractionFailed,
#[error("Serialization error: {0}")]
Serialization(String),
}
pub type AdaptorResult<T> = Result<T, AdaptorError>;
fn random_scalar() -> Scalar {
let mut bytes = [0u8; 32];
rand::rng().fill_bytes(&mut bytes);
Scalar::from_bytes_mod_order(bytes)
}
#[derive(Clone, Serialize, Deserialize)]
pub struct AdaptorSecretKey(Scalar);
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct AdaptorPublicKey(RistrettoPoint);
#[derive(Clone, Serialize, Deserialize)]
pub struct AdaptorSecret(Scalar);
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct AdaptorPoint(RistrettoPoint);
#[derive(Clone)]
pub struct AdaptorSigner {
secret_key: AdaptorSecretKey,
public_key: AdaptorPublicKey,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct PreSignature {
r_prime: RistrettoPoint, s_prime: Scalar, }
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct AdaptorSignature {
r: RistrettoPoint,
s: Scalar,
}
impl AdaptorSecret {
pub fn random() -> Self {
Self(random_scalar())
}
pub fn from_bytes(bytes: &[u8; 32]) -> Self {
Self(Scalar::from_bytes_mod_order(*bytes))
}
pub fn to_bytes(&self) -> [u8; 32] {
self.0.to_bytes()
}
pub fn to_point(&self) -> AdaptorPoint {
AdaptorPoint(RISTRETTO_BASEPOINT_POINT * self.0)
}
}
impl AdaptorPoint {
pub fn from_bytes(bytes: &[u8; 32]) -> AdaptorResult<Self> {
let point = curve25519_dalek::ristretto::CompressedRistretto(*bytes)
.decompress()
.ok_or(AdaptorError::InvalidAdaptorPoint)?;
Ok(Self(point))
}
pub fn to_bytes(&self) -> [u8; 32] {
self.0.compress().to_bytes()
}
}
impl AdaptorSigner {
pub fn new() -> Self {
let secret = random_scalar();
let public = RISTRETTO_BASEPOINT_POINT * secret;
Self {
secret_key: AdaptorSecretKey(secret),
public_key: AdaptorPublicKey(public),
}
}
pub fn from_bytes(bytes: &[u8; 32]) -> AdaptorResult<Self> {
let secret = Scalar::from_bytes_mod_order(*bytes);
let public = RISTRETTO_BASEPOINT_POINT * secret;
Ok(Self {
secret_key: AdaptorSecretKey(secret),
public_key: AdaptorPublicKey(public),
})
}
pub fn public_key(&self) -> AdaptorPublicKey {
self.public_key
}
pub fn to_bytes(&self) -> [u8; 32] {
self.secret_key.0.to_bytes()
}
pub fn create_pre_signature_with_secret(
&self,
message: &[u8],
adaptor_secret: &AdaptorSecret,
) -> AdaptorResult<PreSignature> {
let adaptor = adaptor_secret.to_point();
let k = random_scalar();
let r = RISTRETTO_BASEPOINT_POINT * k;
let r_prime = r + adaptor.0;
let challenge = compute_challenge(&r_prime, &self.public_key, message);
let s_prime = k + challenge * self.secret_key.0;
Ok(PreSignature { r_prime, s_prime })
}
pub fn create_pre_signature(
&self,
message: &[u8],
adaptor: &AdaptorPoint,
) -> AdaptorResult<PreSignature> {
let k = random_scalar();
let r = RISTRETTO_BASEPOINT_POINT * k;
let r_prime = r + adaptor.0;
let challenge = compute_challenge(&r_prime, &self.public_key, message);
let s_prime = k + challenge * self.secret_key.0;
Ok(PreSignature { r_prime, s_prime })
}
}
impl Default for AdaptorSigner {
fn default() -> Self {
Self::new()
}
}
impl AdaptorPublicKey {
pub fn from_bytes(bytes: &[u8; 32]) -> AdaptorResult<Self> {
let point = curve25519_dalek::ristretto::CompressedRistretto(*bytes)
.decompress()
.ok_or(AdaptorError::InvalidPublicKey)?;
Ok(Self(point))
}
pub fn to_bytes(&self) -> [u8; 32] {
self.0.compress().to_bytes()
}
}
fn compute_challenge(r: &RistrettoPoint, pubkey: &AdaptorPublicKey, message: &[u8]) -> Scalar {
let mut hasher = Hasher::new();
hasher.update(&r.compress().to_bytes());
hasher.update(&pubkey.0.compress().to_bytes());
hasher.update(message);
let hash = hasher.finalize();
Scalar::from_bytes_mod_order(*hash.as_bytes())
}
pub fn verify_pre_signature(
pubkey: &AdaptorPublicKey,
message: &[u8],
pre_sig: &PreSignature,
adaptor: &AdaptorPoint,
) -> bool {
let r = pre_sig.r_prime - adaptor.0;
let challenge = compute_challenge(&pre_sig.r_prime, pubkey, message);
let lhs = RISTRETTO_BASEPOINT_POINT * pre_sig.s_prime;
let rhs = r + challenge * pubkey.0;
lhs == rhs
}
pub fn complete_signature(
pre_sig: &PreSignature,
secret: &AdaptorSecret,
) -> AdaptorResult<AdaptorSignature> {
let r = pre_sig.r_prime;
let s = pre_sig.s_prime + secret.0;
Ok(AdaptorSignature { r, s })
}
pub fn verify_adaptor_signature(
pubkey: &AdaptorPublicKey,
message: &[u8],
signature: &AdaptorSignature,
) -> bool {
let challenge = compute_challenge(&signature.r, pubkey, message);
let lhs = RISTRETTO_BASEPOINT_POINT * signature.s;
let rhs = signature.r + challenge * pubkey.0;
lhs == rhs
}
pub fn extract_secret(
pre_sig: &PreSignature,
complete_sig: &AdaptorSignature,
adaptor: &AdaptorPoint,
) -> AdaptorResult<AdaptorSecret> {
let t = complete_sig.s - pre_sig.s_prime;
let computed_adaptor = RISTRETTO_BASEPOINT_POINT * t;
if computed_adaptor != adaptor.0 {
return Err(AdaptorError::SecretExtractionFailed);
}
Ok(AdaptorSecret(t))
}
impl PreSignature {
pub fn to_bytes(&self) -> [u8; 64] {
let mut bytes = [0u8; 64];
bytes[..32].copy_from_slice(&self.r_prime.compress().to_bytes());
bytes[32..].copy_from_slice(&self.s_prime.to_bytes());
bytes
}
pub fn from_bytes(bytes: &[u8; 64]) -> AdaptorResult<Self> {
let r_prime =
curve25519_dalek::ristretto::CompressedRistretto(bytes[..32].try_into().unwrap())
.decompress()
.ok_or(AdaptorError::InvalidSignature)?;
let s_prime = Scalar::from_bytes_mod_order(bytes[32..].try_into().unwrap());
Ok(Self { r_prime, s_prime })
}
}
impl AdaptorSignature {
pub fn to_bytes(&self) -> [u8; 64] {
let mut bytes = [0u8; 64];
bytes[..32].copy_from_slice(&self.r.compress().to_bytes());
bytes[32..].copy_from_slice(&self.s.to_bytes());
bytes
}
pub fn from_bytes(bytes: &[u8; 64]) -> AdaptorResult<Self> {
let r = curve25519_dalek::ristretto::CompressedRistretto(bytes[..32].try_into().unwrap())
.decompress()
.ok_or(AdaptorError::InvalidSignature)?;
let s = Scalar::from_bytes_mod_order(bytes[32..].try_into().unwrap());
Ok(Self { r, s })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_adaptor_basic() {
let secret = AdaptorSecret::random();
let adaptor = secret.to_point();
let signer = AdaptorSigner::new();
let message = b"Test message";
let pre_sig = signer
.create_pre_signature_with_secret(message, &secret)
.unwrap();
assert!(verify_pre_signature(
&signer.public_key(),
message,
&pre_sig,
&adaptor
));
let complete_sig = complete_signature(&pre_sig, &secret).unwrap();
assert!(verify_adaptor_signature(
&signer.public_key(),
message,
&complete_sig
));
let extracted = extract_secret(&pre_sig, &complete_sig, &adaptor).unwrap();
assert_eq!(secret.to_bytes(), extracted.to_bytes());
}
#[test]
fn test_adaptor_wrong_secret() {
let secret = AdaptorSecret::random();
let _adaptor = secret.to_point();
let signer = AdaptorSigner::new();
let message = b"Test message";
let pre_sig = signer
.create_pre_signature_with_secret(message, &secret)
.unwrap();
let wrong_secret = AdaptorSecret::random();
let complete_sig = complete_signature(&pre_sig, &wrong_secret).unwrap();
assert!(!verify_adaptor_signature(
&signer.public_key(),
message,
&complete_sig
));
}
#[test]
fn test_adaptor_wrong_message() {
let secret = AdaptorSecret::random();
let _adaptor = secret.to_point();
let signer = AdaptorSigner::new();
let message = b"Original message";
let pre_sig = signer
.create_pre_signature_with_secret(message, &secret)
.unwrap();
let complete_sig = complete_signature(&pre_sig, &secret).unwrap();
assert!(!verify_adaptor_signature(
&signer.public_key(),
b"Wrong message",
&complete_sig
));
}
#[test]
fn test_secret_extraction_fails_wrong_adaptor() {
let secret = AdaptorSecret::random();
let _adaptor = secret.to_point();
let signer = AdaptorSigner::new();
let message = b"Test message";
let pre_sig = signer
.create_pre_signature_with_secret(message, &secret)
.unwrap();
let complete_sig = complete_signature(&pre_sig, &secret).unwrap();
let wrong_adaptor = AdaptorSecret::random().to_point();
let result = extract_secret(&pre_sig, &complete_sig, &wrong_adaptor);
assert!(result.is_err());
}
#[test]
fn test_pre_signature_serialization() {
let secret = AdaptorSecret::random();
let adaptor = secret.to_point();
let signer = AdaptorSigner::new();
let message = b"Test message";
let pre_sig = signer
.create_pre_signature_with_secret(message, &secret)
.unwrap();
let bytes = pre_sig.to_bytes();
let recovered = PreSignature::from_bytes(&bytes).unwrap();
assert!(verify_pre_signature(
&signer.public_key(),
message,
&recovered,
&adaptor
));
}
#[test]
fn test_complete_signature_serialization() {
let secret = AdaptorSecret::random();
let _adaptor = secret.to_point();
let signer = AdaptorSigner::new();
let message = b"Test message";
let pre_sig = signer
.create_pre_signature_with_secret(message, &secret)
.unwrap();
let complete_sig = complete_signature(&pre_sig, &secret).unwrap();
let bytes = complete_sig.to_bytes();
let recovered = AdaptorSignature::from_bytes(&bytes).unwrap();
assert!(verify_adaptor_signature(
&signer.public_key(),
message,
&recovered
));
}
#[test]
fn test_signer_serialization() {
let signer = AdaptorSigner::new();
let bytes = signer.to_bytes();
let recovered = AdaptorSigner::from_bytes(&bytes).unwrap();
assert_eq!(
signer.public_key().to_bytes(),
recovered.public_key().to_bytes()
);
}
#[test]
fn test_secret_serialization() {
let secret = AdaptorSecret::random();
let bytes = secret.to_bytes();
let recovered = AdaptorSecret::from_bytes(&bytes);
assert_eq!(secret.to_bytes(), recovered.to_bytes());
assert_eq!(
secret.to_point().to_bytes(),
recovered.to_point().to_bytes()
);
}
#[test]
fn test_adaptor_point_serialization() {
let secret = AdaptorSecret::random();
let adaptor = secret.to_point();
let bytes = adaptor.to_bytes();
let recovered = AdaptorPoint::from_bytes(&bytes).unwrap();
assert_eq!(adaptor.to_bytes(), recovered.to_bytes());
}
#[test]
fn test_multiple_pre_signatures_same_message() {
let secret = AdaptorSecret::random();
let adaptor = secret.to_point();
let signer = AdaptorSigner::new();
let message = b"Same message";
let pre_sig1 = signer
.create_pre_signature_with_secret(message, &secret)
.unwrap();
let pre_sig2 = signer
.create_pre_signature_with_secret(message, &secret)
.unwrap();
assert!(verify_pre_signature(
&signer.public_key(),
message,
&pre_sig1,
&adaptor
));
assert!(verify_pre_signature(
&signer.public_key(),
message,
&pre_sig2,
&adaptor
));
assert_ne!(pre_sig1.to_bytes(), pre_sig2.to_bytes());
}
#[test]
fn test_atomic_swap_scenario() {
let alice_secret = AdaptorSecret::random();
let adaptor = alice_secret.to_point();
let bob = AdaptorSigner::new();
let payment_to_alice = b"Payment from Bob to Alice for 1 BTC";
let pre_sig = bob
.create_pre_signature_with_secret(payment_to_alice, &alice_secret)
.unwrap();
assert!(verify_pre_signature(
&bob.public_key(),
payment_to_alice,
&pre_sig,
&adaptor
));
let complete_sig = complete_signature(&pre_sig, &alice_secret).unwrap();
assert!(verify_adaptor_signature(
&bob.public_key(),
payment_to_alice,
&complete_sig
));
let extracted_secret = extract_secret(&pre_sig, &complete_sig, &adaptor).unwrap();
assert_eq!(alice_secret.to_bytes(), extracted_secret.to_bytes());
}
#[test]
fn test_public_key_serialization() {
let signer = AdaptorSigner::new();
let pubkey = signer.public_key();
let bytes = pubkey.to_bytes();
let recovered = AdaptorPublicKey::from_bytes(&bytes).unwrap();
assert_eq!(pubkey.to_bytes(), recovered.to_bytes());
}
#[test]
fn test_deterministic_completion() {
let secret = AdaptorSecret::random();
let _adaptor = secret.to_point();
let signer = AdaptorSigner::new();
let message = b"Test message";
let pre_sig = signer
.create_pre_signature_with_secret(message, &secret)
.unwrap();
let sig1 = complete_signature(&pre_sig, &secret).unwrap();
let sig2 = complete_signature(&pre_sig, &secret).unwrap();
assert_eq!(sig1.to_bytes(), sig2.to_bytes());
}
}