From 52f30a663791a297a1c76fe5e623ae0a31eeaedb Mon Sep 17 00:00:00 2001 From: Lucas Soriano del Pino Date: Thu, 15 Apr 2021 12:39:11 +1000 Subject: [PATCH] Fixing some stuff --- monero-adaptor/src/lib.rs | 314 +++++++++++++++++++++++++------------- 1 file changed, 211 insertions(+), 103 deletions(-) diff --git a/monero-adaptor/src/lib.rs b/monero-adaptor/src/lib.rs index 27b391a9..01013a37 100644 --- a/monero-adaptor/src/lib.rs +++ b/monero-adaptor/src/lib.rs @@ -1,5 +1,6 @@ -use anyhow::Result; -use curve25519_dalek; +#![allow(non_snake_case)] + +use anyhow::{bail, Result}; use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT; use curve25519_dalek::digest::Digest; use curve25519_dalek::ristretto::RistrettoPoint; @@ -33,7 +34,7 @@ fn final_challenge( bytes.append(&mut L.compress().as_bytes().to_vec()); bytes.append(&mut R.compress().as_bytes().to_vec()); - let mut hasher = Sha512::new().chain(bytes); + let hasher = Sha512::new().chain(bytes); let h = Scalar::from_hash(hasher); if i >= RING_SIZE - 2 { @@ -43,25 +44,16 @@ fn final_challenge( } } -struct AdaptorSig; - -fn adaptor_sig( +pub struct AdaptorSig { s_0_a: Scalar, s_0_b: Scalar, + fake_responses: [Scalar; RING_SIZE - 1], h_0: Scalar, - pk: RistrettoPoint, + /// Key image of the real key in the ring. I: RistrettoPoint, -) -> AdaptorSig { - let s_prime_0 = s_0_a + s_0_b; - let l_0 = s_prime_0 * RISTRETTO_BASEPOINT_POINT + h_0 * pk; - - let H_pk: RistrettoPoint = RistrettoPoint::hash_from_bytes::(pk.compress().as_bytes()); - let r_0 = s_prime_0 * H_pk + h_0 * I; - - AdaptorSig } -struct Alice0 { +pub struct Alice0 { // secret index is always 0 ring: [RistrettoPoint; RING_SIZE], fake_responses: [Scalar; RING_SIZE - 1], @@ -77,7 +69,7 @@ struct Alice0 { } impl Alice0 { - fn new( + pub fn new( ring: [RistrettoPoint; RING_SIZE], msg: [u8; 32], R_a: RistrettoPoint, @@ -85,9 +77,8 @@ impl Alice0 { s_prime_a: Scalar, ) -> Self { let mut fake_responses = [Scalar::zero(); RING_SIZE - 1]; - - for i in 0..(RING_SIZE - 1) { - fake_responses[i] = Scalar::random(&mut OsRng); + for response in fake_responses.iter_mut().take(RING_SIZE - 1) { + *response = Scalar::random(&mut OsRng); } Alice0 { @@ -100,7 +91,8 @@ impl Alice0 { alpha_a: Scalar::random(&mut OsRng), } } - fn next_message(&self) -> Message0 { + + pub fn next_message(&self) -> Message0 { let p_k = self.ring.first().unwrap().compress(); // H_p(p_k) let base_key_hashed_to_point: RistrettoPoint = @@ -109,7 +101,7 @@ impl Alice0 { let I_a = self.s_prime_a * base_key_hashed_to_point; let I_hat_a = self.alpha_a * base_key_hashed_to_point; - let T_a = self.s_prime_a * RISTRETTO_BASEPOINT_POINT; + let T_a = self.alpha_a * RISTRETTO_BASEPOINT_POINT; Message0 { pi_a: DleqProof::new( @@ -123,7 +115,7 @@ impl Alice0 { } } - fn receive(self, msg: Message1) -> Result { + pub fn receive(self, msg: Message1) -> Result { let p_k = self.ring.first().unwrap().compress(); let base_key_hashed_to_point: RistrettoPoint = RistrettoPoint::hash_from_bytes::(p_k.as_bytes()); @@ -134,27 +126,33 @@ impl Alice0 { msg.I_hat_b, )?; - let I_a = self.s_prime_a * base_key_hashed_to_point; - let T_a = self.s_prime_a * RISTRETTO_BASEPOINT_POINT; + let T_a = self.alpha_a * RISTRETTO_BASEPOINT_POINT; + let I_hat_a = self.alpha_a * base_key_hashed_to_point; - let h_1 = { - Sha512::new() + let h_0 = { + let h_0 = Sha512::new() .chain(self.msg) .chain((T_a + msg.T_b + self.R_a).compress().as_bytes()) - .chain((I_a + msg.I_b + self.R_prime_a).compress().as_bytes()) + .chain( + (I_hat_a + msg.I_hat_b + self.R_prime_a) + .compress() + .as_bytes(), + ); + Scalar::from_hash(h_0) }; - let h_0 = final_challenge( + let I_a = self.s_prime_a * base_key_hashed_to_point; + let h_last = final_challenge( 1, self.fake_responses, self.ring, - Scalar::from_hash(h_1), + h_0, I_a, msg.I_b, self.msg, ); - let s_0_a = self.alpha_a - h_0 * self.s_prime_a; + let s_0_a = self.alpha_a - h_last * self.s_prime_a; Ok(Alice1 { ring: self.ring, @@ -164,12 +162,14 @@ impl Alice0 { R_prime_a: self.R_prime_a, s_prime_a: self.s_prime_a, alpha_a: self.alpha_a, + h_0, + I_b: msg.I_b, s_0_a, }) } } -struct Alice1 { +pub struct Alice1 { // secret index is always 0 ring: [RistrettoPoint; RING_SIZE], fake_responses: [Scalar; RING_SIZE - 1], @@ -182,25 +182,48 @@ struct Alice1 { s_prime_a: Scalar, // secret value: alpha_a: Scalar, + h_0: Scalar, + I_b: RistrettoPoint, s_0_a: Scalar, } impl Alice1 { - fn next_message(&self) -> Message2 { + pub fn next_message(&self) -> Message2 { let base_key_hashed_to_point: RistrettoPoint = RistrettoPoint::hash_from_bytes::( self.ring.first().unwrap().compress().as_bytes(), ); let I_a = self.s_prime_a * base_key_hashed_to_point; - let T_a = self.s_prime_a * RISTRETTO_BASEPOINT_POINT; + let T_a = self.alpha_a * RISTRETTO_BASEPOINT_POINT; let I_hat_a = self.alpha_a * base_key_hashed_to_point; Message2 { d_a: Opening::new(self.fake_responses, I_a, I_hat_a, T_a), s_0_a: self.s_0_a, } } + + pub fn receive(self, msg: Message3) -> Alice2 { + let base_key_hashed_to_point: RistrettoPoint = RistrettoPoint::hash_from_bytes::( + self.ring.first().unwrap().compress().as_bytes(), + ); + let I_a = self.s_prime_a * base_key_hashed_to_point; + + let adaptor_sig = AdaptorSig { + s_0_a: self.s_0_a, + s_0_b: msg.s_0_b, + fake_responses: self.fake_responses, + h_0: self.h_0, + I: I_a + self.I_b, + }; + + Alice2 { adaptor_sig } + } } -struct Bob0 { +pub struct Alice2 { + pub adaptor_sig: AdaptorSig, +} + +pub struct Bob0 { // secret index is always 0 ring: [RistrettoPoint; RING_SIZE], msg: [u8; 32], @@ -214,24 +237,24 @@ struct Bob0 { } impl Bob0 { - fn new( + pub fn new( ring: [RistrettoPoint; RING_SIZE], msg: [u8; 32], - R_b: RistrettoPoint, - R_prime_b: RistrettoPoint, + R_a: RistrettoPoint, + R_prime_a: RistrettoPoint, s_b: Scalar, ) -> Self { Bob0 { ring, msg, - R_a: R_b, - R_prime_a: R_prime_b, + R_a, + R_prime_a, alpha_b: Scalar::random(&mut OsRng), s_b, } } - fn receive(self, msg: Message0) -> Bob1 { + pub fn receive(self, msg: Message0) -> Bob1 { Bob1 { ring: self.ring, msg: self.msg, @@ -245,7 +268,7 @@ impl Bob0 { } } -struct Bob1 { +pub struct Bob1 { // secret index is always 0 ring: [RistrettoPoint; RING_SIZE], msg: [u8; 32], @@ -261,7 +284,7 @@ struct Bob1 { } impl Bob1 { - fn next_message(&self) -> Message1 { + pub fn next_message(&self) -> Message1 { let p_k = self.ring.first().unwrap().compress(); // H_p(p_k) let base_key_hashed_to_point: RistrettoPoint = @@ -270,7 +293,7 @@ impl Bob1 { let I_b = self.s_b * base_key_hashed_to_point; let I_hat_b = self.alpha_b * base_key_hashed_to_point; - let T_b = self.s_b * RISTRETTO_BASEPOINT_POINT; + let T_b = self.alpha_b * RISTRETTO_BASEPOINT_POINT; Message1 { I_b, @@ -286,78 +309,59 @@ impl Bob1 { } } - fn receive(self, msg: Message2) -> Result { + pub fn receive(self, msg: Message2) -> Result { let (fake_responses, I_a, I_hat_a, T_a) = msg.d_a.open(self.c_a)?; let base_key_hashed_to_point: RistrettoPoint = RistrettoPoint::hash_from_bytes::( self.ring.first().unwrap().compress().as_bytes(), ); - let I_b = self.s_b * base_key_hashed_to_point; - let T_b = self.s_b * RISTRETTO_BASEPOINT_POINT; + self.pi_a.verify( + RISTRETTO_BASEPOINT_POINT, + T_a, + base_key_hashed_to_point, + I_hat_a, + )?; - let h_1 = { - Sha512::new() + let T_b = self.alpha_b * RISTRETTO_BASEPOINT_POINT; + let I_hat_b = self.alpha_b * base_key_hashed_to_point; + + let h_0 = { + let h_0 = Sha512::new() .chain(self.msg) .chain((T_a + T_b + self.R_a).compress().as_bytes()) - .chain((I_a + I_b + self.R_prime_a).compress().as_bytes()) + .chain((I_hat_a + I_hat_b + self.R_prime_a).compress().as_bytes()); + Scalar::from_hash(h_0) }; - let h_0 = final_challenge( - 1, - fake_responses, - self.ring, - Scalar::from_hash(h_1), - I_a, - I_b, - self.msg, - ); + let I_b = self.s_b * base_key_hashed_to_point; + let h_last = final_challenge(1, fake_responses, self.ring, h_0, I_a, I_b, self.msg); - let s_0_b = self.alpha_b - h_0 * self.s_b; + let s_0_b = self.alpha_b - h_last * self.s_b; - Ok(Bob2 { - ring: self.ring, - msg: self.msg, - R_b: self.R_a, - R_prime_b: self.R_prime_a, - s_b: self.s_b, - alpha_b: self.alpha_b, - pi_a: self.pi_a, - fake_responses, - I_a: I_b, - I_hat_a, - T_a: T_b, + let adaptor_sig = AdaptorSig { s_0_a: msg.s_0_a, s_0_b, - }) + fake_responses, + h_0, + I: I_a + I_b, + }; + + Ok(Bob2 { s_0_b, adaptor_sig }) } } -struct Bob2 { - // secret index is always 0 - ring: [RistrettoPoint; RING_SIZE], - msg: [u8; 32], - // encryption key - R_b: RistrettoPoint, - // R'a = r_a*H_p(p_k) where p_k is the signing public key - R_prime_b: RistrettoPoint, - s_b: Scalar, - alpha_b: Scalar, - // secret value: +pub struct Bob2 { s_0_b: Scalar, - s_0_a: Scalar, - pi_a: DleqProof, - fake_responses: [Scalar; RING_SIZE - 1], - I_a: RistrettoPoint, - I_hat_a: RistrettoPoint, - T_a: RistrettoPoint, + pub adaptor_sig: AdaptorSig, } impl Bob2 { - fn next_message(&self) -> Message3 { + pub fn next_message(&self) -> Message3 { Message3 { s_0_b: self.s_0_b } } } + struct DleqProof { s: Scalar, c: Scalar, @@ -371,7 +375,22 @@ impl DleqProof { xH: RistrettoPoint, x: Scalar, ) -> Self { - todo!() + let r = Scalar::random(&mut OsRng); + let rG = r * G; + let rH = r * H; + + let hash = Sha512::new() + .chain(dbg!(G.compress()).as_bytes()) + .chain(dbg!(xG.compress()).as_bytes()) + .chain(dbg!(H.compress()).as_bytes()) + .chain(dbg!(xH.compress()).as_bytes()) + .chain(dbg!(rG.compress()).as_bytes()) + .chain(dbg!(rH.compress()).as_bytes()); + let c = Scalar::from_hash(hash); + + let s = r + c * x; + + Self { s, c } } fn verify( &self, @@ -380,11 +399,40 @@ impl DleqProof { H: RistrettoPoint, xH: RistrettoPoint, ) -> Result<()> { - todo!() + let s = self.s; + let c = self.c; + + let rG = { + let sG = s * G; + + sG - c * xG + }; + + let rH = { + let sH = s * H; + + sH - c * xH + }; + + let hash = Sha512::new() + .chain(dbg!(G.compress()).as_bytes()) + .chain(dbg!(xG.compress()).as_bytes()) + .chain(dbg!(H.compress()).as_bytes()) + .chain(dbg!(xH.compress()).as_bytes()) + .chain(dbg!(rG.compress()).as_bytes()) + .chain(dbg!(rH.compress()).as_bytes()); + let c_prime = Scalar::from_hash(hash); + + if c != c_prime { + bail!("invalid DLEQ proof") + } + + Ok(()) } } -struct Commitment([u8; 32]); +#[derive(PartialEq)] +struct Commitment([u8; 64]); impl Commitment { fn new( @@ -393,7 +441,22 @@ impl Commitment { I_hat_a: RistrettoPoint, T_a: RistrettoPoint, ) -> Self { - todo!() + let fake_responses = fake_responses + .iter() + .flat_map(|r| r.as_bytes().to_vec()) + .collect::>(); + + let hash = Sha512::new() + .chain(fake_responses) + .chain(I_a.compress().as_bytes()) + .chain(I_hat_a.compress().as_bytes()) + .chain(T_a.compress().as_bytes()) + .finalize(); + + let mut commitment = [0u8; 64]; + commitment.copy_from_slice(&hash); + + Self(commitment) } } @@ -418,27 +481,35 @@ impl Opening { T_a, } } + fn open( self, - c_a: Commitment, + commitment: Commitment, ) -> Result<( [Scalar; RING_SIZE - 1], RistrettoPoint, RistrettoPoint, RistrettoPoint, )> { - Ok((todo!())) + let self_commitment = + Commitment::new(self.fake_responses, self.I_a, self.I_hat_a, self.T_a); + + if self_commitment == commitment { + Ok((self.fake_responses, self.I_a, self.I_hat_a, self.T_a)) + } else { + bail!("opening does not match commitment") + } } } // Alice Sends this to Bob -struct Message0 { +pub struct Message0 { c_a: Commitment, pi_a: DleqProof, } // Bob sends this to ALice -struct Message1 { +pub struct Message1 { I_b: RistrettoPoint, T_b: RistrettoPoint, I_hat_b: RistrettoPoint, @@ -446,13 +517,13 @@ struct Message1 { } // Alice sends this to Bob -struct Message2 { +pub struct Message2 { d_a: Opening, s_0_a: Scalar, } // Bob sends this to Alice -struct Message3 { +pub struct Message3 { s_0_b: Scalar, } @@ -462,7 +533,44 @@ mod tests { #[test] fn sign_and_verify_success() { - let mut fake_responses = [Scalar::random(&mut OsRng); RING_SIZE - 1]; - dbg!(fake_responses); + let msg = b"hello world, monero is amazing!!"; + + let s_prime_a = Scalar::random(&mut OsRng); + let s_b = Scalar::random(&mut OsRng); + + let pk = (s_prime_a + s_b) * RISTRETTO_BASEPOINT_POINT; + + let (r_a, R_a, R_prime_a) = { + let r_a = Scalar::random(&mut OsRng); + let R_a = r_a * RISTRETTO_BASEPOINT_POINT; + + let pk_hashed_to_point: RistrettoPoint = + RistrettoPoint::hash_from_bytes::(pk.compress().as_bytes()); + let R_prime_a = r_a * pk_hashed_to_point; + + (r_a, R_a, R_prime_a) + }; + + let mut ring = [RistrettoPoint::default(); RING_SIZE]; + ring[0] = pk; + + for member in ring[1..].iter_mut().take(RING_SIZE - 1) { + *member = RistrettoPoint::random(&mut OsRng); + } + + let alice = Alice0::new(ring, *msg, R_a, R_prime_a, s_prime_a); + let bob = Bob0::new(ring, *msg, R_a, R_prime_a, s_b); + + let msg = alice.next_message(); + let bob = bob.receive(msg); + + let msg = bob.next_message(); + let alice = alice.receive(msg).unwrap(); + + let msg = alice.next_message(); + let bob = bob.receive(msg).unwrap(); + + let msg = bob.next_message(); + let alice = alice.receive(msg); } }