From a64a114bec96342dab415d34e58b934684b6f12a Mon Sep 17 00:00:00 2001 From: rishflab Date: Thu, 15 Apr 2021 09:20:06 +1000 Subject: [PATCH] Confused about how the ring part works --- Cargo.lock | 93 +++++++- Cargo.toml | 2 +- monero-adaptor/Cargo.toml | 16 ++ monero-adaptor/src/lib.rs | 468 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 571 insertions(+), 8 deletions(-) create mode 100644 monero-adaptor/Cargo.toml create mode 100644 monero-adaptor/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 0eb2eaa2..3e0853da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -639,6 +639,15 @@ dependencies = [ "vec_map", ] +[[package]] +name = "clear_on_drop" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9cc5db465b294c3fa986d5bbb0f3017cd850bff6dd6c52f9ccff8b4d21b7b08" +dependencies = [ + "cc", +] + [[package]] name = "cloudabi" version = "0.0.3" @@ -648,6 +657,18 @@ dependencies = [ "bitflags", ] +[[package]] +name = "clsag" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66ea6461bc0d5e7e762be243266e621318b4ff6740415ab0190d60cd07385e64" +dependencies = [ + "curve25519-dalek 1.2.6", + "merlin", + "rand 0.6.5", + "sha2 0.8.2", +] + [[package]] name = "config" version = "0.11.0" @@ -815,6 +836,20 @@ dependencies = [ "memchr", ] +[[package]] +name = "curve25519-dalek" +version = "1.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d59fed08e452f286b251f88b2fc64a01f50a7b263aa09557ad7285d9e7fa" +dependencies = [ + "byteorder", + "clear_on_drop", + "digest 0.8.1", + "rand_core 0.3.1", + "serde", + "subtle 2.4.0", +] + [[package]] name = "curve25519-dalek" version = "3.0.2" @@ -941,7 +976,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ - "curve25519-dalek", + "curve25519-dalek 3.0.2", "ed25519", "rand 0.7.3", "serde", @@ -1646,6 +1681,12 @@ dependencies = [ "syn", ] +[[package]] +name = "keccak" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" + [[package]] name = "keccak-hash" version = "0.7.0" @@ -1794,7 +1835,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36db0f0db3b0433f5b9463f1c0cd9eadc0a3734a9170439ce501ff99733a88bd" dependencies = [ "bytes 1.0.1", - "curve25519-dalek", + "curve25519-dalek 3.0.2", "futures", "lazy_static", "libp2p-core", @@ -2011,6 +2052,18 @@ dependencies = [ "autocfg 1.0.1", ] +[[package]] +name = "merlin" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b0942b357c1b4d0dc43ba724674ec89c3218e6ca2b3e8269e7cb53bcecd2f6e" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.4.2", + "zeroize", +] + [[package]] name = "mime" version = "0.2.6" @@ -2095,7 +2148,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dad9cdd100bffa1b21e9b1052394dd78246c6977b9e6f801b4acfd53ba62311e" dependencies = [ "base58-monero", - "curve25519-dalek", + "curve25519-dalek 3.0.2", "fixed-hash", "hex 0.4.3", "hex-literal", @@ -2105,6 +2158,21 @@ dependencies = [ "thiserror", ] +[[package]] +name = "monero-adaptor" +version = "0.1.0" +dependencies = [ + "anyhow", + "clsag", + "curve25519-dalek 3.0.2", + "hex 0.4.3", + "monero", + "nazgul", + "rand 0.7.3", + "sha2 0.9.3", + "tokio 1.4.0", +] + [[package]] name = "monero-harness" version = "0.1.0" @@ -2137,7 +2205,7 @@ dependencies = [ name = "monero-wallet" version = "0.1.0" dependencies = [ - "curve25519-dalek", + "curve25519-dalek 3.0.2", "hex 0.4.3", "monero", "monero-harness", @@ -2193,6 +2261,17 @@ dependencies = [ "unsigned-varint 0.7.0", ] +[[package]] +name = "nazgul" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dff2f512a99611eb14f9bbdcc69e900c93952c4cc94656d2278ea5aa294cec2" +dependencies = [ + "curve25519-dalek 3.0.2", + "digest 0.9.0", + "rand_core 0.5.1", +] + [[package]] name = "nohash-hasher" version = "0.2.0" @@ -3327,7 +3406,7 @@ name = "sigma_fun" version = "0.1.3-alpha.0" source = "git+https://github.com/LLFourn/secp256kfun#8538ef22498170960a9769df2700c1986cc540fd" dependencies = [ - "curve25519-dalek", + "curve25519-dalek 3.0.2", "digest 0.9.0", "generic-array 0.14.4", "rand_core 0.5.1", @@ -3599,7 +3678,7 @@ dependencies = [ "bmrng", "config", "conquer-once", - "curve25519-dalek", + "curve25519-dalek 3.0.2", "dialoguer", "directories-next", "ecdsa_fun", @@ -4530,7 +4609,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc614d95359fd7afc321b66d2107ede58b246b844cf5d8a0adcca413e439f088" dependencies = [ - "curve25519-dalek", + "curve25519-dalek 3.0.2", "rand_core 0.5.1", "zeroize", ] diff --git a/Cargo.toml b/Cargo.toml index 02e9cc6f..11ea1a99 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["monero-harness", "monero-rpc", "swap", "monero-wallet"] +members = ["monero-adaptor", "monero-harness", "monero-rpc", "swap", "monero-wallet"] diff --git a/monero-adaptor/Cargo.toml b/monero-adaptor/Cargo.toml new file mode 100644 index 00000000..8d4f66ae --- /dev/null +++ b/monero-adaptor/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "monero-adaptor" +version = "0.1.0" +authors = ["CoBloX Team "] +edition = "2018" + +[dependencies] +monero = "0.11" +anyhow = "1" +hex = "0.4" +tokio = { version = "1", features = ["rt-multi-thread", "time", "macros", "sync", "process", "fs"] } +curve25519-dalek = "3" +rand = "0.7" +nazgul = "0.1" +clsag = "0.3" +sha2 = "0.9" diff --git a/monero-adaptor/src/lib.rs b/monero-adaptor/src/lib.rs new file mode 100644 index 00000000..27b391a9 --- /dev/null +++ b/monero-adaptor/src/lib.rs @@ -0,0 +1,468 @@ +use anyhow::Result; +use curve25519_dalek; +use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT; +use curve25519_dalek::digest::Digest; +use curve25519_dalek::ristretto::RistrettoPoint; +use curve25519_dalek::scalar::Scalar; +use rand::rngs::OsRng; +use sha2::Sha512; + +const RING_SIZE: usize = 11; + +fn final_challenge( + i: usize, + fake_responses: [Scalar; RING_SIZE - 1], + ring: [RistrettoPoint; RING_SIZE], + h_prev: Scalar, + I_a: RistrettoPoint, + I_b: RistrettoPoint, + msg: [u8; 32], +) -> Scalar { + let L = fake_responses[i] * RISTRETTO_BASEPOINT_POINT + h_prev * ring[i]; + + let H_pk_i: RistrettoPoint = + RistrettoPoint::hash_from_bytes::(ring[i].compress().as_bytes()); + + let I = I_a + I_b; + let R = fake_responses[i] * H_pk_i + I; + + let mut bytes = vec![]; + + // todo: add tag and ring + bytes.append(&mut msg.to_vec()); + 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 h = Scalar::from_hash(hasher); + + if i >= RING_SIZE - 2 { + h + } else { + final_challenge(i + 1, fake_responses, ring, h, I_a, I_b, msg) + } +} + +struct AdaptorSig; + +fn adaptor_sig( + s_0_a: Scalar, + s_0_b: Scalar, + h_0: Scalar, + pk: RistrettoPoint, + 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 { + // secret index is always 0 + ring: [RistrettoPoint; RING_SIZE], + fake_responses: [Scalar; RING_SIZE - 1], + msg: [u8; 32], + // encryption key + R_a: RistrettoPoint, + // R'a = r_a*H_p(p_k) where p_k is the signing public key + R_prime_a: RistrettoPoint, + // this is not s_a cos of something to with one-time-address?? + s_prime_a: Scalar, + // secret value: + alpha_a: Scalar, +} + +impl Alice0 { + fn new( + ring: [RistrettoPoint; RING_SIZE], + msg: [u8; 32], + R_a: RistrettoPoint, + R_prime_a: RistrettoPoint, + 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); + } + + Alice0 { + ring, + fake_responses, + msg, + R_a, + R_prime_a, + s_prime_a, + alpha_a: Scalar::random(&mut OsRng), + } + } + fn next_message(&self) -> Message0 { + let p_k = self.ring.first().unwrap().compress(); + // H_p(p_k) + let base_key_hashed_to_point: RistrettoPoint = + RistrettoPoint::hash_from_bytes::(p_k.as_bytes()); + // key image + 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; + + Message0 { + pi_a: DleqProof::new( + RISTRETTO_BASEPOINT_POINT, + T_a, + base_key_hashed_to_point, + I_hat_a, + self.s_prime_a, + ), + c_a: Commitment::new(self.fake_responses, I_a, I_hat_a, T_a), + } + } + + 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()); + msg.pi_b.verify( + RISTRETTO_BASEPOINT_POINT, + msg.T_b, + base_key_hashed_to_point, + 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 h_1 = { + 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()) + }; + + let h_0 = final_challenge( + 1, + self.fake_responses, + self.ring, + Scalar::from_hash(h_1), + I_a, + msg.I_b, + self.msg, + ); + + let s_0_a = self.alpha_a - h_0 * self.s_prime_a; + + Ok(Alice1 { + ring: self.ring, + fake_responses: self.fake_responses, + msg: self.msg, + R_a: self.R_a, + R_prime_a: self.R_prime_a, + s_prime_a: self.s_prime_a, + alpha_a: self.alpha_a, + s_0_a, + }) + } +} + +struct Alice1 { + // secret index is always 0 + ring: [RistrettoPoint; RING_SIZE], + fake_responses: [Scalar; RING_SIZE - 1], + msg: [u8; 32], + // encryption key + R_a: RistrettoPoint, + // R'a = r_a*H_p(p_k) where p_k is the signing public key + R_prime_a: RistrettoPoint, + // this is not s_a cos of something to with one-time-address?? + s_prime_a: Scalar, + // secret value: + alpha_a: Scalar, + s_0_a: Scalar, +} + +impl Alice1 { + 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 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, + } + } +} + +struct Bob0 { + // secret index is always 0 + ring: [RistrettoPoint; RING_SIZE], + msg: [u8; 32], + // encryption key + R_a: RistrettoPoint, + // R'a = r_a*H_p(p_k) where p_k is the signing public key + R_prime_a: RistrettoPoint, + s_b: Scalar, + // secret value: + alpha_b: Scalar, +} + +impl Bob0 { + fn new( + ring: [RistrettoPoint; RING_SIZE], + msg: [u8; 32], + R_b: RistrettoPoint, + R_prime_b: RistrettoPoint, + s_b: Scalar, + ) -> Self { + Bob0 { + ring, + msg, + R_a: R_b, + R_prime_a: R_prime_b, + alpha_b: Scalar::random(&mut OsRng), + s_b, + } + } + + fn receive(self, msg: Message0) -> Bob1 { + Bob1 { + ring: self.ring, + msg: self.msg, + R_a: self.R_a, + R_prime_a: self.R_prime_a, + s_b: self.s_b, + alpha_b: self.alpha_b, + pi_a: msg.pi_a, + c_a: msg.c_a, + } + } +} + +struct Bob1 { + // secret index is always 0 + ring: [RistrettoPoint; RING_SIZE], + msg: [u8; 32], + // encryption key + R_a: RistrettoPoint, + // R'a = r_a*H_p(p_k) where p_k is the signing public key + R_prime_a: RistrettoPoint, + s_b: Scalar, + // secret value: + alpha_b: Scalar, + pi_a: DleqProof, + c_a: Commitment, +} + +impl Bob1 { + fn next_message(&self) -> Message1 { + let p_k = self.ring.first().unwrap().compress(); + // H_p(p_k) + let base_key_hashed_to_point: RistrettoPoint = + RistrettoPoint::hash_from_bytes::(p_k.as_bytes()); + // key image + 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; + + Message1 { + I_b, + T_b, + I_hat_b, + pi_b: DleqProof::new( + RISTRETTO_BASEPOINT_POINT, + T_b, + base_key_hashed_to_point, + I_hat_b, + self.s_b, + ), + } + } + + 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; + + let h_1 = { + 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()) + }; + + let h_0 = final_challenge( + 1, + fake_responses, + self.ring, + Scalar::from_hash(h_1), + I_a, + I_b, + self.msg, + ); + + let s_0_b = self.alpha_b - h_0 * 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, + s_0_a: msg.s_0_a, + s_0_b, + }) + } +} + +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: + 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, +} + +impl Bob2 { + fn next_message(&self) -> Message3 { + Message3 { s_0_b: self.s_0_b } + } +} +struct DleqProof { + s: Scalar, + c: Scalar, +} + +impl DleqProof { + fn new( + G: RistrettoPoint, + xG: RistrettoPoint, + H: RistrettoPoint, + xH: RistrettoPoint, + x: Scalar, + ) -> Self { + todo!() + } + fn verify( + &self, + G: RistrettoPoint, + xG: RistrettoPoint, + H: RistrettoPoint, + xH: RistrettoPoint, + ) -> Result<()> { + todo!() + } +} + +struct Commitment([u8; 32]); + +impl Commitment { + fn new( + fake_responses: [Scalar; RING_SIZE - 1], + I_a: RistrettoPoint, + I_hat_a: RistrettoPoint, + T_a: RistrettoPoint, + ) -> Self { + todo!() + } +} + +struct Opening { + fake_responses: [Scalar; RING_SIZE - 1], + I_a: RistrettoPoint, + I_hat_a: RistrettoPoint, + T_a: RistrettoPoint, +} + +impl Opening { + fn new( + fake_responses: [Scalar; RING_SIZE - 1], + I_a: RistrettoPoint, + I_hat_a: RistrettoPoint, + T_a: RistrettoPoint, + ) -> Self { + Self { + fake_responses, + I_a, + I_hat_a, + T_a, + } + } + fn open( + self, + c_a: Commitment, + ) -> Result<( + [Scalar; RING_SIZE - 1], + RistrettoPoint, + RistrettoPoint, + RistrettoPoint, + )> { + Ok((todo!())) + } +} + +// Alice Sends this to Bob +struct Message0 { + c_a: Commitment, + pi_a: DleqProof, +} + +// Bob sends this to ALice +struct Message1 { + I_b: RistrettoPoint, + T_b: RistrettoPoint, + I_hat_b: RistrettoPoint, + pi_b: DleqProof, +} + +// Alice sends this to Bob +struct Message2 { + d_a: Opening, + s_0_a: Scalar, +} + +// Bob sends this to Alice +struct Message3 { + s_0_b: Scalar, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sign_and_verify_success() { + let mut fake_responses = [Scalar::random(&mut OsRng); RING_SIZE - 1]; + dbg!(fake_responses); + } +}