diff --git a/src/amf/franking.rs b/src/amf/franking.rs index b676e30..b254344 100644 --- a/src/amf/franking.rs +++ b/src/amf/franking.rs @@ -1,4 +1,4 @@ -//! AMF Franking Algorithms (KeyGen, Frank, Verify, Judge) +//! AMF Franking Algorithms (KeyGen, Frank, Verify, Judge, Forge, RForge, JForge) //! //! Cf. Fig. 5 in [AMF] //! @@ -64,7 +64,7 @@ pub struct AMFSignature { pub fn keygen(role: AMFRole) -> (AMFPublicKey, AMFSecretKey) { // cf. Fig. 5 in [AMF] let mut rng = rand::thread_rng(); - let g = RistrettoBasepointTable::basepoint(&RISTRETTO_BASEPOINT_TABLE); + let g = RistrettoBasepointTable::basepoint(RISTRETTO_BASEPOINT_TABLE); let secret_key = Scalar::random(&mut rng); let public_key = secret_key * g; ( @@ -81,7 +81,7 @@ pub fn frank( message: &[u8], ) -> AMFSignature { let mut rng = rand::thread_rng(); - let g = RistrettoBasepointTable::basepoint(&RISTRETTO_BASEPOINT_TABLE); + let g = RistrettoBasepointTable::basepoint(RISTRETTO_BASEPOINT_TABLE); // cf. Fig. 5 in [AMF] let alpha = Scalar::random(&mut rng); let beta = Scalar::random(&mut rng); @@ -162,6 +162,139 @@ pub fn judge( b1 && b2 } +pub fn forge( + sender_public_key: AMFPublicKey, + _recipient_public_key: AMFPublicKey, + judge_public_key: AMFPublicKey, + message: &[u8], +) -> AMFSignature { + let mut rng = rand::thread_rng(); + let g = RistrettoBasepointTable::basepoint(RISTRETTO_BASEPOINT_TABLE); + // cf. Fig. 5 in [AMF] + let alpha = Scalar::random(&mut rng); + let beta = Scalar::random(&mut rng); + let gamma = Scalar::random(&mut rng); + let delta = Scalar::random(&mut rng); + + let J = gamma * g; + let R = delta * g; + let E_J = alpha * g; + let E_R = beta * g; + + let mut spok = AMFSPoK::new( + sender_public_key.public_key, + judge_public_key.public_key, + J, + R, + E_J, + ); + let pi = spok.sign( + FiatShamirSecretKey { + witness: ( + OrWitness { + b: true, + s0_witness: None, + s1_witness: Some(gamma), + }, + OrWitness { + b: true, + s0_witness: None, + s1_witness: Some(delta), + }, + ), + }, + message, + ); + AMFSignature { pi, J, R, E_J, E_R } +} + +pub fn r_forge( + sender_public_key: AMFPublicKey, + recipient_secret_key: AMFSecretKey, + judge_public_key: AMFPublicKey, + message: &[u8], +) -> AMFSignature { + let mut rng = rand::thread_rng(); + let g = RistrettoBasepointTable::basepoint(RISTRETTO_BASEPOINT_TABLE); + // cf. Fig. 5 in [AMF] + let alpha = Scalar::random(&mut rng); + let beta = Scalar::random(&mut rng); + let gamma = Scalar::random(&mut rng); + + let recipient_public_key = recipient_secret_key.secret_key * g; + + let J = gamma * g; + let R = beta * recipient_public_key; + let E_J = alpha * g; + let E_R = beta * g; + + let mut spok = AMFSPoK::new( + sender_public_key.public_key, + judge_public_key.public_key, + J, + R, + E_J, + ); + let pi = spok.sign( + FiatShamirSecretKey { + witness: ( + OrWitness { + b: true, + s0_witness: None, + s1_witness: Some(gamma), + }, + OrWitness { + b: true, + s0_witness: None, + s1_witness: Some(beta * recipient_secret_key.secret_key), + }, + ), + }, + message, + ); + AMFSignature { pi, J, R, E_J, E_R } +} + +pub fn j_forge( + sender_public_key: AMFPublicKey, + recipient_public_key: AMFPublicKey, + judge_secret_key: AMFSecretKey, + message: &[u8], +) -> AMFSignature { + let mut rng = rand::thread_rng(); + let g = RistrettoBasepointTable::basepoint(RISTRETTO_BASEPOINT_TABLE); + // cf. Fig. 5 in [AMF] + let alpha = Scalar::random(&mut rng); + let beta = Scalar::random(&mut rng); + + let judge_public_key = judge_secret_key.secret_key * g; + + let J = alpha * judge_public_key; + let R = beta * recipient_public_key.public_key; + let E_J = alpha * g; + let E_R = beta * g; + + let mut spok = AMFSPoK::new(sender_public_key.public_key, judge_public_key, J, R, E_J); + let pi = spok.sign( + FiatShamirSecretKey { + witness: ( + OrWitness { + b: true, + s0_witness: None, + s1_witness: Some(alpha * judge_secret_key.secret_key), + }, + OrWitness { + b: false, + s0_witness: Some(alpha), + s1_witness: None, + }, + ), + }, + message, + ); + AMFSignature { pi, J, R, E_J, E_R } +} + #[cfg(test)] mod tests { use super::*; @@ -209,4 +342,153 @@ mod tests { ); assert!(judging_result); } + + #[test] + fn test_forge() { + let (sender_public_key, _sender_secret_key) = keygen(AMFRole::Sender); + let (recipient_public_key, recipient_secret_key) = keygen(AMFRole::Recipient); + let (judge_public_key, judge_secret_key) = keygen(AMFRole::Judge); + + let message = b"hello world!"; + + // Forge an AMF signature for "universal deniability" + let amf_signature = forge( + sender_public_key, + recipient_public_key, + judge_public_key, + message, + ); + + // The forged signature should NOT be verified by the recipient + let verification_result = verify( + recipient_secret_key, + sender_public_key, + recipient_public_key, + judge_public_key, + message, + amf_signature, + ); + assert!(!verification_result); + + // The forged signature should NOT be judged by the judge, as the judge can detect the forgery + let judging_result = judge( + judge_secret_key, + sender_public_key, + recipient_public_key, + judge_public_key, + message, + amf_signature, + ); + assert!(!judging_result); + + // The forged signature should look valid + let spok = AMFSPoK::new( + sender_public_key.public_key, + judge_public_key.public_key, + amf_signature.J, + amf_signature.R, + amf_signature.E_J, + ); + assert!(spok.verify(message, amf_signature.pi)); + } + + #[test] + fn test_r_forge() { + let (sender_public_key, _sender_secret_key) = keygen(AMFRole::Sender); + let (recipient_public_key, recipient_secret_key) = keygen(AMFRole::Recipient); + let (judge_public_key, judge_secret_key) = keygen(AMFRole::Judge); + + let message = b"hello world!"; + + // Forge the AMF signature using the recipient's secret key + // This enables "receiver compromise deniability" + let amf_signature = r_forge( + sender_public_key, + recipient_secret_key, + judge_public_key, + message, + ); + + // The forged signature should be verified by any party with the recipient's secret key + let verification_result = verify( + recipient_secret_key, + sender_public_key, + recipient_public_key, + judge_public_key, + message, + amf_signature, + ); + assert!(verification_result); + + // The forged signature should NOT be judged by the judge, as the judge can detect the forgery + // This is what maintains "receiver binding" + let judging_result = judge( + judge_secret_key, + sender_public_key, + recipient_public_key, + judge_public_key, + message, + amf_signature, + ); + assert!(!judging_result); + + // The forged signature should look valid + let spok = AMFSPoK::new( + sender_public_key.public_key, + judge_public_key.public_key, + amf_signature.J, + amf_signature.R, + amf_signature.E_J, + ); + assert!(spok.verify(message, amf_signature.pi)); + } + + #[test] + fn test_j_forge() { + let (sender_public_key, _sender_secret_key) = keygen(AMFRole::Sender); + let (recipient_public_key, recipient_secret_key) = keygen(AMFRole::Recipient); + let (judge_public_key, judge_secret_key) = keygen(AMFRole::Judge); + + let message = b"hello world!"; + + // Forge an AMF signature for "judge compromise deniability" + let amf_signature = j_forge( + sender_public_key, + recipient_public_key, + judge_secret_key, + message, + ); + + // The forged signature should be verified by the recipient + let verification_result = verify( + recipient_secret_key, + sender_public_key, + recipient_public_key, + judge_public_key, + message, + amf_signature, + ); + assert!(verification_result); + + // The forged signature should be judged by the judge + let judging_result = judge( + judge_secret_key, + sender_public_key, + recipient_public_key, + judge_public_key, + message, + amf_signature, + ); + assert!(judging_result); + + // The forged signature should look valid + let spok = AMFSPoK::new( + sender_public_key.public_key, + judge_public_key.public_key, + amf_signature.J, + amf_signature.R, + amf_signature.E_J, + ); + assert!(spok.verify(message, amf_signature.pi)); + } } diff --git a/src/pok/linear_sigma.rs b/src/pok/linear_sigma.rs index 26e54ca..7ec5081 100644 --- a/src/pok/linear_sigma.rs +++ b/src/pok/linear_sigma.rs @@ -73,7 +73,7 @@ impl GenericSigmaProver { pub fn new(witness_statement: WitnessStatement) -> Self { - let g = RistrettoBasepointTable::basepoint(&RISTRETTO_BASEPOINT_TABLE); + let g = RistrettoBasepointTable::basepoint(RISTRETTO_BASEPOINT_TABLE); Self { g, witness: None, @@ -85,7 +85,7 @@ impl impl GenericSigmaVerifier { pub fn new(witness_statement: WitnessStatement) -> Self { - let g = RistrettoBasepointTable::basepoint(&RISTRETTO_BASEPOINT_TABLE); + let g = RistrettoBasepointTable::basepoint(RISTRETTO_BASEPOINT_TABLE); Self { g, witness_statement,