From 3148e54cc157fb8acbf4b247de67fe78ec16f7dd Mon Sep 17 00:00:00 2001 From: arnaucube Date: Sat, 9 Apr 2022 17:23:59 +0200 Subject: [PATCH] Add bLSAG signature generation --- .gitignore | 2 + Cargo.toml | 15 ++++++ src/lib.rs | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 150 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..646b89d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "ring-signatures" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ark-std = "0.3.0" +ark-ff = "0.3.0" +ark-ec = "0.3.0" +ark-ed-on-bn254 = "0.3.0" +sha2 = "0.10.2" +rand = { version = "0.8", features = [ "std", "std_rng" ] } +lazy_static = "1.4.0" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..c22fc4f --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,133 @@ +extern crate ark_ed_on_bn254; +use ark_ec::{AffineCurve, ProjectiveCurve, TEModelParameters}; +use ark_ed_on_bn254::{EdwardsAffine, EdwardsParameters, EdwardsProjective, FqParameters, Fr}; +use ark_ff::{bytes::FromBytes, fields::PrimeField, BigInteger, Fp256}; +use ark_std::{rand, UniformRand, Zero}; +use sha2::{Digest, Sha256}; + +const GX: Fp256 = ::AFFINE_GENERATOR_COEFFS.0; +const GY: Fp256 = ::AFFINE_GENERATOR_COEFFS.1; + +#[macro_use] +extern crate lazy_static; + +lazy_static! { + static ref G_AFFINE: EdwardsAffine = EdwardsAffine::new(GX, GY); + pub static ref G: EdwardsProjective = G_AFFINE.into_projective(); +} + +pub type PublicKey = EdwardsProjective; +pub type Signature = (Fr, Vec); + +#[derive(Debug, PartialEq)] +pub struct KeyPair { + sk: Fr, + pub pk: PublicKey, +} + +pub fn new_key() -> KeyPair { + let mut rng = ark_std::rand::thread_rng(); + let sk: Fr = Fr::rand(&mut rng); + // let sk: Fr = UniformRand::rand(&mut rng); + + let pk = G.mul(sk.into_repr()); + KeyPair { sk, pk } +} + +impl KeyPair { + pub fn key_image(&self) -> EdwardsProjective { + hash_to_point(self.pk).mul(self.sk.into_repr()) + } + + pub fn sign(&self, ring: Vec, m: Vec) -> Signature { + let ring_size = ring.len(); + // determine pi (the position of signer's public key in R + let mut pi = 0; + let mut found = false; + for i in 0..ring_size { + if self.pk == ring[i] { + pi = i; + found = true; + break; + } + } + if !found { + // error + println!("key not found in the ring"); + } + + let mut rng = ark_std::rand::thread_rng(); + let a: Fr = Fr::rand(&mut rng); + let mut r: Vec = vec![Fr::zero(); ring_size]; + + // for i \in {1, 2, ..., n} \ {i=pi} + for i in 0..ring_size { + if i == pi { + continue; + } + r[i] = Fr::rand(&mut rng); + } + + let mut c: Vec = vec![Fr::zero(); ring_size]; + // c_{pi+1} + let pi1 = (pi + 1) % ring_size; + c[pi1] = hash( + &ring, + &m, + G.mul(a.into_repr()), + hash_to_point(ring[pi]).mul(a.into_repr()), + ); + + let key_image = self.key_image(); + // do c_{i+1} from i=pi+1 to pi-1: + for j in 0..(ring_size - 1) { + let i = (pi1 + j) % ring_size; + let i1 = (pi1 + j + 1) % ring_size; + c[i1] = hash( + &ring, + &m, + G.mul(r[i].into_repr()) + ring[i].mul(c[i].into_repr()), + hash_to_point(ring[i]).mul(r[i].into_repr()) + key_image.mul(c[i].into_repr()), + ); + println!("i {:?}, {:?}", i, c[i1]); + } + + // compute r_pi + r[pi] = a - c[pi] * self.sk; + (c[0], r) + } +} + +fn hash_to_point(a: EdwardsProjective) -> EdwardsProjective { + // TODO use a proper hash_to_point method + let mut v: Vec = Vec::new(); + v.append(&mut a.into_affine().x.into_repr().to_bytes_le()); + v.append(&mut a.into_affine().y.into_repr().to_bytes_le()); + let mut hasher = Sha256::new(); + hasher.update(v); + let h = hasher.finalize(); + let v = Fr::from_le_bytes_mod_order(&h[..]); + + G.mul(v.into_repr()) +} + +fn hash(ring: &Vec, m: &Vec, a: EdwardsProjective, b: EdwardsProjective) -> Fr { + let mut v: Vec = Vec::new(); + + for i in 0..ring.len() { + v.append(&mut ring[i].into_affine().x.into_repr().to_bytes_le()); + v.append(&mut ring[i].into_affine().y.into_repr().to_bytes_le()); + } + v.append(&mut m.clone()); + v.append(&mut a.into_affine().x.into_repr().to_bytes_le()); + v.append(&mut a.into_affine().y.into_repr().to_bytes_le()); + v.append(&mut b.into_affine().x.into_repr().to_bytes_le()); + v.append(&mut b.into_affine().y.into_repr().to_bytes_le()); + + Fr::from_le_bytes_mod_order(&Sha256::new().chain_update(v).finalize()) +} + +#[cfg(test)] +mod tests { + use super::*; +}