mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2025-02-25 09:01:21 -05:00
Add Monero adaptor signature protocol
This commit is contained in:
parent
e7785d2c83
commit
99fd1c84d9
152
Cargo.lock
generated
152
Cargo.lock
generated
@ -323,6 +323,29 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.58.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f8523b410d7187a43085e7e064416ea32ded16bd0a4e6fc025e21616d01258f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"clap",
|
||||
"env_logger",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"log 0.4.14",
|
||||
"peeking_take_while",
|
||||
"proc-macro2 1.0.24",
|
||||
"quote 1.0.9",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
"which 3.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitcoin"
|
||||
version = "0.26.0"
|
||||
@ -554,6 +577,15 @@ version = "1.0.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
@ -602,6 +634,17 @@ dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "853eda514c284c2287f4bf20ae614f8781f40a81d32ecda6e91449304dfe077c"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.3"
|
||||
@ -1006,6 +1049,19 @@ dependencies = [
|
||||
"syn 1.0.64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"humantime",
|
||||
"log 0.4.14",
|
||||
"regex",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fake-simd"
|
||||
version = "0.1.2"
|
||||
@ -1279,6 +1335,12 @@ dependencies = [
|
||||
"polyval",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.1"
|
||||
@ -1304,6 +1366,16 @@ version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3"
|
||||
|
||||
[[package]]
|
||||
name = "hash_edwards_to_edwards"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/comit-network/hash_edwards_to_edwards#e9ea43626706e6cf812ad86566dca5bbf2066ee0"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"cc",
|
||||
"curve25519-dalek",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.9.1"
|
||||
@ -1434,6 +1506,12 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05842d0d43232b23ccb7060ecb0f0626922c21f30012e97b767b30afd4a5d4b9"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.10.16"
|
||||
@ -1702,6 +1780,12 @@ version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "lexical-core"
|
||||
version = "0.7.5"
|
||||
@ -1721,6 +1805,16 @@ version = "0.2.90"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba4aede83fc3617411dc6993bc8c70919750c1c257c6ca6a502aed6e0e2394ae"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libp2p"
|
||||
version = "0.37.1"
|
||||
@ -2170,6 +2264,17 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "monero-adaptor"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"curve25519-dalek",
|
||||
"hash_edwards_to_edwards",
|
||||
"rand 0.7.3",
|
||||
"tiny-keccak",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "monero-epee-bin-serde"
|
||||
version = "1.0.0"
|
||||
@ -2475,6 +2580,12 @@ dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peeking_take_while"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
||||
|
||||
[[package]]
|
||||
name = "pem"
|
||||
version = "0.8.3"
|
||||
@ -2717,7 +2828,7 @@ dependencies = [
|
||||
"prost",
|
||||
"prost-types",
|
||||
"tempfile",
|
||||
"which",
|
||||
"which 4.0.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3144,6 +3255,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hex"
|
||||
version = "2.1.0"
|
||||
@ -3450,6 +3567,12 @@ dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42a568c8f2cd051a4d283bd6eb0343ac214c1b0f1ac19f93e1175b2dee38c73d"
|
||||
|
||||
[[package]]
|
||||
name = "sigma_fun"
|
||||
version = "0.1.3-alpha.0"
|
||||
@ -3855,6 +3978,15 @@ dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.1.16"
|
||||
@ -4634,6 +4766,15 @@ dependencies = [
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "3.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.0.2"
|
||||
@ -4678,6 +4819,15 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
|
@ -1,5 +1,5 @@
|
||||
[workspace]
|
||||
members = [ "monero-harness", "monero-rpc", "swap", "monero-wallet" ]
|
||||
members = ["monero-adaptor", "monero-harness", "monero-rpc", "swap", "monero-wallet"]
|
||||
|
||||
[patch.crates-io]
|
||||
torut = { git = "https://github.com/bonomat/torut/", branch = "feature-flag-tor-secret-keys", default-features = false, features = [ "v3", "control" ] }
|
||||
|
12
monero-adaptor/Cargo.toml
Normal file
12
monero-adaptor/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "monero-adaptor"
|
||||
version = "0.1.0"
|
||||
authors = ["CoBloX Team <team@coblox.tech>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
curve25519-dalek = "3"
|
||||
rand = "0.7"
|
||||
tiny-keccak = { version = "2", features = ["keccak"] }
|
||||
hash_edwards_to_edwards = { git = "https://github.com/comit-network/hash_edwards_to_edwards" }
|
655
monero-adaptor/src/lib.rs
Normal file
655
monero-adaptor/src/lib.rs
Normal file
@ -0,0 +1,655 @@
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use curve25519_dalek::constants::ED25519_BASEPOINT_POINT;
|
||||
use curve25519_dalek::edwards::EdwardsPoint;
|
||||
use curve25519_dalek::scalar::Scalar;
|
||||
use hash_edwards_to_edwards::hash_point_to_point;
|
||||
use rand::rngs::OsRng;
|
||||
use std::convert::TryInto;
|
||||
use tiny_keccak::{Hasher, Keccak};
|
||||
|
||||
const RING_SIZE: usize = 11;
|
||||
const DOMAIN_TAG: &str = "CSLAG_c";
|
||||
|
||||
fn challenge(
|
||||
s_i: Scalar,
|
||||
pk_i: EdwardsPoint,
|
||||
h_prev: Scalar,
|
||||
I: EdwardsPoint,
|
||||
mut prefix: Keccak,
|
||||
) -> Result<Scalar> {
|
||||
let L_i = s_i * ED25519_BASEPOINT_POINT + h_prev * pk_i;
|
||||
|
||||
let H_p_pk_i = hash_point_to_point(pk_i);
|
||||
|
||||
let R_i = s_i * H_p_pk_i + h_prev * I;
|
||||
|
||||
prefix.update(&L_i.compress().as_bytes().to_vec());
|
||||
prefix.update(&R_i.compress().as_bytes().to_vec());
|
||||
|
||||
let mut output = [0u8; 64];
|
||||
prefix.finalize(&mut output);
|
||||
|
||||
Ok(Scalar::from_bytes_mod_order_wide(&output))
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn final_challenge(
|
||||
fake_responses: [Scalar; RING_SIZE - 1],
|
||||
ring: [EdwardsPoint; RING_SIZE],
|
||||
T_a: EdwardsPoint,
|
||||
T_b: EdwardsPoint,
|
||||
R_a: EdwardsPoint,
|
||||
I_hat_a: EdwardsPoint,
|
||||
I_hat_b: EdwardsPoint,
|
||||
R_prime_a: EdwardsPoint,
|
||||
I_a: EdwardsPoint,
|
||||
I_b: EdwardsPoint,
|
||||
msg: [u8; 32],
|
||||
) -> Result<(Scalar, Scalar)> {
|
||||
let h_0 = {
|
||||
let ring = ring
|
||||
.iter()
|
||||
.flat_map(|pk| pk.compress().as_bytes().to_vec())
|
||||
.collect::<Vec<u8>>();
|
||||
|
||||
let mut keccak = tiny_keccak::Keccak::v512();
|
||||
keccak.update(DOMAIN_TAG.as_bytes());
|
||||
keccak.update(ring.as_slice());
|
||||
keccak.update(&msg);
|
||||
keccak.update((T_a + T_b + R_a).compress().as_bytes());
|
||||
keccak.update((I_hat_a + I_hat_b + R_prime_a).compress().as_bytes());
|
||||
let mut output = [0u8; 64];
|
||||
keccak.finalize(&mut output);
|
||||
|
||||
Scalar::from_bytes_mod_order_wide(&output)
|
||||
};
|
||||
// ring size is 11
|
||||
|
||||
let ring_concat = ring
|
||||
.iter()
|
||||
.flat_map(|pk| pk.compress().as_bytes().to_vec())
|
||||
.collect::<Vec<u8>>();
|
||||
|
||||
let mut keccak = tiny_keccak::Keccak::v512();
|
||||
keccak.update(DOMAIN_TAG.as_bytes());
|
||||
keccak.update(ring_concat.as_slice());
|
||||
keccak.update(&msg);
|
||||
|
||||
let I = I_a + I_b;
|
||||
|
||||
let h_last = fake_responses
|
||||
.iter()
|
||||
.enumerate()
|
||||
.fold(h_0, |h_prev, (i, s_i)| {
|
||||
let pk_i = ring[i + 1];
|
||||
// TODO: Do not unwrap here
|
||||
challenge(*s_i, pk_i, h_prev, I, keccak.clone()).unwrap()
|
||||
});
|
||||
|
||||
Ok((h_last, h_0))
|
||||
}
|
||||
|
||||
pub struct AdaptorSignature {
|
||||
s_0_a: Scalar,
|
||||
s_0_b: Scalar,
|
||||
fake_responses: [Scalar; RING_SIZE - 1],
|
||||
h_0: Scalar,
|
||||
/// Key image of the real key in the ring.
|
||||
I: EdwardsPoint,
|
||||
}
|
||||
|
||||
impl AdaptorSignature {
|
||||
pub fn adapt(self, y: Scalar) -> Signature {
|
||||
let r_last = self.s_0_a + self.s_0_b + y;
|
||||
|
||||
let responses = self
|
||||
.fake_responses
|
||||
.iter()
|
||||
.chain([r_last].iter())
|
||||
.copied()
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
.expect("correct response size");
|
||||
|
||||
Signature {
|
||||
responses,
|
||||
h_0: self.h_0,
|
||||
I: self.I,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Signature {
|
||||
pub responses: [Scalar; RING_SIZE],
|
||||
pub h_0: Scalar,
|
||||
/// Key image of the real key in the ring.
|
||||
pub I: EdwardsPoint,
|
||||
}
|
||||
|
||||
impl Signature {
|
||||
#[cfg(test)]
|
||||
fn verify(&self, ring: [EdwardsPoint; RING_SIZE], msg: &[u8; 32]) -> Result<bool> {
|
||||
let ring_concat = ring
|
||||
.iter()
|
||||
.flat_map(|pk| pk.compress().as_bytes().to_vec())
|
||||
.collect::<Vec<u8>>();
|
||||
|
||||
let mut prefix = tiny_keccak::Keccak::v512();
|
||||
prefix.update(DOMAIN_TAG.as_bytes());
|
||||
prefix.update(ring_concat.as_slice());
|
||||
prefix.update(msg);
|
||||
|
||||
let mut h = self.h_0;
|
||||
|
||||
for (i, s_i) in self.responses.iter().enumerate() {
|
||||
let pk_i = ring[(i + 1) % RING_SIZE];
|
||||
h = challenge(*s_i, pk_i, h, self.I, prefix.clone())?;
|
||||
}
|
||||
|
||||
Ok(h == self.h_0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Alice0 {
|
||||
// secret index is always 0
|
||||
ring: [EdwardsPoint; RING_SIZE],
|
||||
fake_responses: [Scalar; RING_SIZE - 1],
|
||||
msg: [u8; 32],
|
||||
// encryption key
|
||||
R_a: EdwardsPoint,
|
||||
// R'a = r_a*H_p(p_k) where p_k is the signing public key
|
||||
R_prime_a: EdwardsPoint,
|
||||
// this is not s_a cos of something to with one-time-address??
|
||||
s_prime_a: Scalar,
|
||||
// secret value:
|
||||
alpha_a: Scalar,
|
||||
H_p_pk: EdwardsPoint,
|
||||
I_a: EdwardsPoint,
|
||||
I_hat_a: EdwardsPoint,
|
||||
T_a: EdwardsPoint,
|
||||
}
|
||||
|
||||
impl Alice0 {
|
||||
pub fn new(
|
||||
ring: [EdwardsPoint; RING_SIZE],
|
||||
msg: [u8; 32],
|
||||
R_a: EdwardsPoint,
|
||||
R_prime_a: EdwardsPoint,
|
||||
s_prime_a: Scalar,
|
||||
) -> Result<Self> {
|
||||
let mut fake_responses = [Scalar::zero(); RING_SIZE - 1];
|
||||
for response in fake_responses.iter_mut().take(RING_SIZE - 1) {
|
||||
*response = Scalar::random(&mut OsRng);
|
||||
}
|
||||
let alpha_a = Scalar::random(&mut OsRng);
|
||||
|
||||
let p_k = ring[0];
|
||||
let H_p_pk = hash_point_to_point(p_k);
|
||||
|
||||
let I_a = s_prime_a * H_p_pk;
|
||||
let I_hat_a = alpha_a * H_p_pk;
|
||||
let T_a = alpha_a * ED25519_BASEPOINT_POINT;
|
||||
|
||||
Ok(Alice0 {
|
||||
ring,
|
||||
fake_responses,
|
||||
msg,
|
||||
R_a,
|
||||
R_prime_a,
|
||||
s_prime_a,
|
||||
alpha_a,
|
||||
H_p_pk,
|
||||
I_a,
|
||||
I_hat_a,
|
||||
T_a,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn next_message(&self) -> Message0 {
|
||||
Message0 {
|
||||
pi_a: DleqProof::new(
|
||||
ED25519_BASEPOINT_POINT,
|
||||
self.T_a,
|
||||
self.H_p_pk,
|
||||
self.I_hat_a,
|
||||
self.alpha_a,
|
||||
),
|
||||
c_a: Commitment::new(self.fake_responses, self.I_a, self.I_hat_a, self.T_a),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receive(self, msg: Message1) -> Result<Alice1> {
|
||||
msg.pi_b
|
||||
.verify(ED25519_BASEPOINT_POINT, msg.T_b, self.H_p_pk, msg.I_hat_b)?;
|
||||
|
||||
let (h_last, h_0) = final_challenge(
|
||||
self.fake_responses,
|
||||
self.ring,
|
||||
self.T_a,
|
||||
msg.T_b,
|
||||
self.R_a,
|
||||
self.I_hat_a,
|
||||
msg.I_hat_b,
|
||||
self.R_prime_a,
|
||||
self.I_a,
|
||||
msg.I_b,
|
||||
self.msg,
|
||||
)?;
|
||||
|
||||
let s_0_a = self.alpha_a - h_last * self.s_prime_a;
|
||||
|
||||
Ok(Alice1 {
|
||||
fake_responses: self.fake_responses,
|
||||
h_0,
|
||||
I_b: msg.I_b,
|
||||
s_0_a,
|
||||
I_a: self.I_a,
|
||||
I_hat_a: self.I_hat_a,
|
||||
T_a: self.T_a,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Alice1 {
|
||||
fake_responses: [Scalar; RING_SIZE - 1],
|
||||
I_a: EdwardsPoint,
|
||||
I_hat_a: EdwardsPoint,
|
||||
T_a: EdwardsPoint,
|
||||
h_0: Scalar,
|
||||
I_b: EdwardsPoint,
|
||||
s_0_a: Scalar,
|
||||
}
|
||||
|
||||
impl Alice1 {
|
||||
pub fn next_message(&self) -> Message2 {
|
||||
Message2 {
|
||||
d_a: Opening::new(self.fake_responses, self.I_a, self.I_hat_a, self.T_a),
|
||||
s_0_a: self.s_0_a,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receive(self, msg: Message3) -> Alice2 {
|
||||
let adaptor_sig = AdaptorSignature {
|
||||
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: self.I_a + self.I_b,
|
||||
};
|
||||
|
||||
Alice2 { adaptor_sig }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Alice2 {
|
||||
pub adaptor_sig: AdaptorSignature,
|
||||
}
|
||||
|
||||
pub struct Bob0 {
|
||||
// secret index is always 0
|
||||
ring: [EdwardsPoint; RING_SIZE],
|
||||
msg: [u8; 32],
|
||||
// encryption key
|
||||
R_a: EdwardsPoint,
|
||||
// R'a = r_a*H_p(p_k) where p_k is the signing public key
|
||||
R_prime_a: EdwardsPoint,
|
||||
s_b: Scalar,
|
||||
// secret value:
|
||||
alpha_b: Scalar,
|
||||
H_p_pk: EdwardsPoint,
|
||||
I_b: EdwardsPoint,
|
||||
I_hat_b: EdwardsPoint,
|
||||
T_b: EdwardsPoint,
|
||||
}
|
||||
|
||||
impl Bob0 {
|
||||
pub fn new(
|
||||
ring: [EdwardsPoint; RING_SIZE],
|
||||
msg: [u8; 32],
|
||||
R_a: EdwardsPoint,
|
||||
R_prime_a: EdwardsPoint,
|
||||
s_b: Scalar,
|
||||
) -> Result<Self> {
|
||||
let alpha_b = Scalar::random(&mut OsRng);
|
||||
|
||||
let p_k = ring[0];
|
||||
let H_p_pk = hash_point_to_point(p_k);
|
||||
|
||||
let I_b = s_b * H_p_pk;
|
||||
let I_hat_b = alpha_b * H_p_pk;
|
||||
let T_b = alpha_b * ED25519_BASEPOINT_POINT;
|
||||
|
||||
Ok(Bob0 {
|
||||
ring,
|
||||
msg,
|
||||
R_a,
|
||||
R_prime_a,
|
||||
s_b,
|
||||
alpha_b,
|
||||
H_p_pk,
|
||||
I_b,
|
||||
I_hat_b,
|
||||
T_b,
|
||||
})
|
||||
}
|
||||
|
||||
pub 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,
|
||||
H_p_pk: self.H_p_pk,
|
||||
I_b: self.I_b,
|
||||
I_hat_b: self.I_hat_b,
|
||||
T_b: self.T_b,
|
||||
pi_a: msg.pi_a,
|
||||
c_a: msg.c_a,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Bob1 {
|
||||
// secret index is always 0
|
||||
ring: [EdwardsPoint; RING_SIZE],
|
||||
msg: [u8; 32],
|
||||
// encryption key
|
||||
R_a: EdwardsPoint,
|
||||
// R'a = r_a*H_p(p_k) where p_k is the signing public key
|
||||
R_prime_a: EdwardsPoint,
|
||||
s_b: Scalar,
|
||||
// secret value:
|
||||
alpha_b: Scalar,
|
||||
H_p_pk: EdwardsPoint,
|
||||
I_b: EdwardsPoint,
|
||||
I_hat_b: EdwardsPoint,
|
||||
T_b: EdwardsPoint,
|
||||
pi_a: DleqProof,
|
||||
c_a: Commitment,
|
||||
}
|
||||
|
||||
impl Bob1 {
|
||||
pub fn next_message(&self) -> Message1 {
|
||||
Message1 {
|
||||
I_b: self.I_b,
|
||||
T_b: self.T_b,
|
||||
I_hat_b: self.I_hat_b,
|
||||
pi_b: DleqProof::new(
|
||||
ED25519_BASEPOINT_POINT,
|
||||
self.T_b,
|
||||
self.H_p_pk,
|
||||
self.I_hat_b,
|
||||
self.alpha_b,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receive(self, msg: Message2) -> Result<Bob2> {
|
||||
let (fake_responses, I_a, I_hat_a, T_a) = msg.d_a.open(self.c_a)?;
|
||||
|
||||
self.pi_a
|
||||
.verify(ED25519_BASEPOINT_POINT, T_a, self.H_p_pk, I_hat_a)?;
|
||||
|
||||
let (h_last, h_0) = final_challenge(
|
||||
fake_responses,
|
||||
self.ring,
|
||||
T_a,
|
||||
self.T_b,
|
||||
self.R_a,
|
||||
I_hat_a,
|
||||
self.I_hat_b,
|
||||
self.R_prime_a,
|
||||
I_a,
|
||||
self.I_b,
|
||||
self.msg,
|
||||
)?;
|
||||
|
||||
let s_0_b = self.alpha_b - h_last * self.s_b;
|
||||
|
||||
let adaptor_sig = AdaptorSignature {
|
||||
s_0_a: msg.s_0_a,
|
||||
s_0_b,
|
||||
fake_responses,
|
||||
h_0,
|
||||
I: I_a + self.I_b,
|
||||
};
|
||||
|
||||
Ok(Bob2 { s_0_b, adaptor_sig })
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Bob2 {
|
||||
s_0_b: Scalar,
|
||||
pub adaptor_sig: AdaptorSignature,
|
||||
}
|
||||
|
||||
impl Bob2 {
|
||||
pub fn next_message(&self) -> Message3 {
|
||||
Message3 { s_0_b: self.s_0_b }
|
||||
}
|
||||
}
|
||||
|
||||
struct DleqProof {
|
||||
s: Scalar,
|
||||
c: Scalar,
|
||||
}
|
||||
|
||||
impl DleqProof {
|
||||
fn new(
|
||||
G: EdwardsPoint,
|
||||
xG: EdwardsPoint,
|
||||
H: EdwardsPoint,
|
||||
xH: EdwardsPoint,
|
||||
x: Scalar,
|
||||
) -> Self {
|
||||
let r = Scalar::random(&mut OsRng);
|
||||
let rG = r * G;
|
||||
let rH = r * H;
|
||||
|
||||
let mut keccak = tiny_keccak::Keccak::v256();
|
||||
keccak.update(G.compress().as_bytes());
|
||||
keccak.update(xG.compress().as_bytes());
|
||||
keccak.update(H.compress().as_bytes());
|
||||
keccak.update(xH.compress().as_bytes());
|
||||
keccak.update(rG.compress().as_bytes());
|
||||
keccak.update(rH.compress().as_bytes());
|
||||
|
||||
let mut output = [0u8; 32];
|
||||
keccak.finalize(&mut output);
|
||||
|
||||
let c = Scalar::from_bytes_mod_order(output);
|
||||
|
||||
let s = r + c * x;
|
||||
|
||||
Self { s, c }
|
||||
}
|
||||
|
||||
fn verify(
|
||||
&self,
|
||||
G: EdwardsPoint,
|
||||
xG: EdwardsPoint,
|
||||
H: EdwardsPoint,
|
||||
xH: EdwardsPoint,
|
||||
) -> Result<()> {
|
||||
let s = self.s;
|
||||
let c = self.c;
|
||||
|
||||
let rG = (s * G) + (-c * xG);
|
||||
let rH = (s * H) + (-c * xH);
|
||||
|
||||
let mut keccak = tiny_keccak::Keccak::v256();
|
||||
keccak.update(G.compress().as_bytes());
|
||||
keccak.update(xG.compress().as_bytes());
|
||||
keccak.update(H.compress().as_bytes());
|
||||
keccak.update(xH.compress().as_bytes());
|
||||
keccak.update(rG.compress().as_bytes());
|
||||
keccak.update(rH.compress().as_bytes());
|
||||
|
||||
let mut output = [0u8; 32];
|
||||
keccak.finalize(&mut output);
|
||||
|
||||
let c_prime = Scalar::from_bytes_mod_order(output);
|
||||
|
||||
if c != c_prime {
|
||||
bail!("invalid DLEQ proof")
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
struct Commitment([u8; 32]);
|
||||
|
||||
impl Commitment {
|
||||
fn new(
|
||||
fake_responses: [Scalar; RING_SIZE - 1],
|
||||
I_a: EdwardsPoint,
|
||||
I_hat_a: EdwardsPoint,
|
||||
T_a: EdwardsPoint,
|
||||
) -> Self {
|
||||
let fake_responses = fake_responses
|
||||
.iter()
|
||||
.flat_map(|r| r.as_bytes().to_vec())
|
||||
.collect::<Vec<u8>>();
|
||||
|
||||
let mut keccak = tiny_keccak::Keccak::v256();
|
||||
keccak.update(&fake_responses);
|
||||
keccak.update(I_a.compress().as_bytes());
|
||||
keccak.update(I_hat_a.compress().as_bytes());
|
||||
keccak.update(T_a.compress().as_bytes());
|
||||
|
||||
let mut output = [0u8; 32];
|
||||
keccak.finalize(&mut output);
|
||||
|
||||
Self(output)
|
||||
}
|
||||
}
|
||||
|
||||
struct Opening {
|
||||
fake_responses: [Scalar; RING_SIZE - 1],
|
||||
I_a: EdwardsPoint,
|
||||
I_hat_a: EdwardsPoint,
|
||||
T_a: EdwardsPoint,
|
||||
}
|
||||
|
||||
impl Opening {
|
||||
fn new(
|
||||
fake_responses: [Scalar; RING_SIZE - 1],
|
||||
I_a: EdwardsPoint,
|
||||
I_hat_a: EdwardsPoint,
|
||||
T_a: EdwardsPoint,
|
||||
) -> Self {
|
||||
Self {
|
||||
fake_responses,
|
||||
I_a,
|
||||
I_hat_a,
|
||||
T_a,
|
||||
}
|
||||
}
|
||||
|
||||
fn open(
|
||||
self,
|
||||
commitment: Commitment,
|
||||
) -> Result<(
|
||||
[Scalar; RING_SIZE - 1],
|
||||
EdwardsPoint,
|
||||
EdwardsPoint,
|
||||
EdwardsPoint,
|
||||
)> {
|
||||
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
|
||||
pub struct Message0 {
|
||||
c_a: Commitment,
|
||||
pi_a: DleqProof,
|
||||
}
|
||||
|
||||
// Bob sends this to ALice
|
||||
pub struct Message1 {
|
||||
I_b: EdwardsPoint,
|
||||
T_b: EdwardsPoint,
|
||||
I_hat_b: EdwardsPoint,
|
||||
pi_b: DleqProof,
|
||||
}
|
||||
|
||||
// Alice sends this to Bob
|
||||
pub struct Message2 {
|
||||
d_a: Opening,
|
||||
s_0_a: Scalar,
|
||||
}
|
||||
|
||||
// Bob sends this to Alice
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Message3 {
|
||||
s_0_b: Scalar,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn sign_and_verify_success() {
|
||||
let msg_to_sign = 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) * ED25519_BASEPOINT_POINT;
|
||||
|
||||
let (r_a, R_a, R_prime_a) = {
|
||||
let r_a = Scalar::random(&mut OsRng);
|
||||
let R_a = r_a * ED25519_BASEPOINT_POINT;
|
||||
|
||||
let pk_hashed_to_point = hash_point_to_point(pk);
|
||||
|
||||
let R_prime_a = r_a * pk_hashed_to_point;
|
||||
|
||||
(r_a, R_a, R_prime_a)
|
||||
};
|
||||
|
||||
let mut ring = [EdwardsPoint::default(); RING_SIZE];
|
||||
ring[0] = pk;
|
||||
|
||||
ring[1..].fill_with(|| {
|
||||
let x = Scalar::random(&mut OsRng);
|
||||
|
||||
x * ED25519_BASEPOINT_POINT
|
||||
});
|
||||
|
||||
let alice = Alice0::new(ring, *msg_to_sign, R_a, R_prime_a, s_prime_a).unwrap();
|
||||
let bob = Bob0::new(ring, *msg_to_sign, R_a, R_prime_a, s_b).unwrap();
|
||||
|
||||
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);
|
||||
|
||||
let sig = alice.adaptor_sig.adapt(r_a);
|
||||
|
||||
assert!(sig.verify(ring, msg_to_sign).unwrap());
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
[toolchain]
|
||||
channel = "nightly-2021-01-31"
|
||||
channel = "nightly-2021-04-15"
|
||||
components = ["rustfmt", "clippy"]
|
||||
targets = ["armv7-unknown-linux-gnueabihf"]
|
||||
|
Loading…
x
Reference in New Issue
Block a user