ring-signatures-rs/src/lib.rs
src/lib.rsRaw
1extern crate ark_ed_on_bn254;
2use ark_ec::{AffineCurve, ProjectiveCurve, TEModelParameters};
3use ark_ed_on_bn254::{EdwardsAffine, EdwardsParameters, EdwardsProjective, FqParameters, Fr};
4use ark_ff::{fields::PrimeField, BigInteger, Fp256};
5use ark_std::{UniformRand, Zero};
6use sha2::{Digest, Sha256};
7
8const GX: Fp256<FqParameters> = <EdwardsParameters as TEModelParameters>::AFFINE_GENERATOR_COEFFS.0;
9const GY: Fp256<FqParameters> = <EdwardsParameters as TEModelParameters>::AFFINE_GENERATOR_COEFFS.1;
10
11#[macro_use]
12extern crate lazy_static;
13
14lazy_static! {
15 static ref G_AFFINE: EdwardsAffine = EdwardsAffine::new(GX, GY);
16 pub static ref G: EdwardsProjective = G_AFFINE.into_projective();
17}
18
19pub type PublicKey = EdwardsProjective;
20pub type Signature = (Fr, Vec<Fr>);
21
22#[derive(Debug, PartialEq)]
23pub struct KeyPair {
24 sk: Fr,
25 pub pk: PublicKey,
26}
27
28pub fn new_key() -> KeyPair {
29 let mut rng = ark_std::rand::thread_rng();
30 let sk: Fr = Fr::rand(&mut rng);
31 // let sk: Fr = UniformRand::rand(&mut rng);
32
33 let pk = G.mul(sk.into_repr());
34 KeyPair { sk, pk }
35}
36
37#[allow(clippy::many_single_char_names)]
38impl KeyPair {
39 pub fn key_image(&self) -> EdwardsProjective {
40 hash_to_point(self.pk).mul(self.sk.into_repr())
41 }
42
43 pub fn sign(&self, ring: Vec<PublicKey>, m: Vec<u8>) -> Result<Signature, String> {
44 let ring_size = ring.len();
45 // determine pi (the position of signer's public key in R
46 let mut pi = 0;
47 let mut found = false;
48 // for i in 0..ring_size {
49 for (i, ring_key) in ring.iter().enumerate() {
50 if &self.pk == ring_key {
51 pi = i;
52 found = true;
53 break;
54 }
55 }
56 if !found {
57 return Err("key not found in the ring".to_string());
58 }
59
60 let mut rng = ark_std::rand::thread_rng();
61 let a: Fr = Fr::rand(&mut rng);
62 let mut r: Vec<Fr> = vec![Fr::zero(); ring_size];
63
64 // for i \in {1, 2, ..., n} \ {i=pi}
65 #[allow(clippy::needless_range_loop)]
66 for i in 0..ring_size {
67 if i == pi {
68 continue;
69 }
70 r[i] = Fr::rand(&mut rng);
71 }
72
73 let mut c: Vec<Fr> = vec![Fr::zero(); ring_size];
74 // c_{pi+1}
75 let pi1 = (pi + 1) % ring_size;
76 c[pi1] = hash(
77 &ring,
78 &m,
79 G.mul(a.into_repr()),
80 hash_to_point(ring[pi]).mul(a.into_repr()),
81 );
82
83 let key_image = self.key_image();
84 // do c_{i+1} from i=pi+1 to pi-1:
85 for j in 0..(ring_size - 1) {
86 let i = (pi1 + j) % ring_size;
87 let i1 = (pi1 + j + 1) % ring_size;
88 c[i1] = hash(
89 &ring,
90 &m,
91 G.mul(r[i].into_repr()) + ring[i].mul(c[i].into_repr()),
92 hash_to_point(ring[i]).mul(r[i].into_repr()) + key_image.mul(c[i].into_repr()),
93 );
94 println!("i {:?}, {:?}", i, c[i1]);
95 }
96
97 // compute r_pi
98 r[pi] = a - c[pi] * self.sk;
99 Ok((c[0], r))
100 }
101}
102
103pub fn verify(
104 ring: Vec<PublicKey>,
105 m: Vec<u8>,
106 key_image: EdwardsProjective,
107 sig: Signature,
108) -> bool {
109 let ring_size = ring.len();
110
111 let c1 = sig.0;
112 let r = sig.1;
113 if ring_size != r.len() {
114 return false;
115 }
116 // TODO check that key_image \in G (EC), by l * key_image == 0
117
118 let mut c: Vec<Fr> = vec![Fr::zero(); ring_size];
119 c[0] = c1;
120 for j in 0..ring_size {
121 let i = j % ring_size;
122 let i1 = (j + 1) % ring_size;
123 c[i1] = hash(
124 &ring,
125 &m,
126 G.mul(r[i].into_repr()) + ring[i].mul(c[i].into_repr()),
127 hash_to_point(ring[i]).mul(r[i].into_repr()) + key_image.mul(c[i].into_repr()),
128 );
129 }
130
131 println!("c {:?}\n{:?}", c1, c[0]);
132
133 if c1 == c[0] {
134 return true;
135 }
136 false
137}
138
139fn hash_to_point(a: EdwardsProjective) -> EdwardsProjective {
140 // TODO use a proper hash_to_point method
141 let mut v: Vec<u8> = Vec::new();
142 v.append(&mut a.into_affine().x.into_repr().to_bytes_le());
143 v.append(&mut a.into_affine().y.into_repr().to_bytes_le());
144 let mut hasher = Sha256::new();
145 hasher.update(v);
146 let h = hasher.finalize();
147 let v = Fr::from_le_bytes_mod_order(&h[..]);
148
149 G.mul(v.into_repr())
150}
151
152fn hash(ring: &[PublicKey], m: &[u8], a: EdwardsProjective, b: EdwardsProjective) -> Fr {
153 let mut v: Vec<u8> = Vec::new();
154
155 for ring_key in ring.iter() {
156 v.append(&mut ring_key.into_affine().x.into_repr().to_bytes_le());
157 v.append(&mut ring_key.into_affine().y.into_repr().to_bytes_le());
158 }
159 v.append(&mut m.to_vec());
160 v.append(&mut a.into_affine().x.into_repr().to_bytes_le());
161 v.append(&mut a.into_affine().y.into_repr().to_bytes_le());
162 v.append(&mut b.into_affine().x.into_repr().to_bytes_le());
163 v.append(&mut b.into_affine().y.into_repr().to_bytes_le());
164
165 Fr::from_le_bytes_mod_order(&Sha256::new().chain_update(v).finalize())
166}
167
168#[cfg(test)]
169mod tests {
170 use super::*;
171
172 #[test]
173 #[allow(non_snake_case)]
174 fn test_bLSAG() {
175 let n = 5; // ring size
176 let pi = 3; // position of prover key in the ring
177
178 let k_pi = new_key();
179 println!("{:?}", k_pi);
180
181 // generate other n public keys
182 let mut ring: Vec<PublicKey> = vec![G.clone(); n];
183 for i in 0..n {
184 let k = new_key();
185 ring[i] = k.pk;
186 }
187 // set K_pi
188 ring[pi] = k_pi.pk;
189
190 let m: Vec<u8> = vec![1, 2, 3, 4];
191 let sig = k_pi.sign(ring.clone(), m.clone()).unwrap();
192 println!("sig {:?}", sig);
193
194 let key_image = k_pi.key_image();
195
196 let v = verify(ring.clone(), m.clone(), key_image, sig.clone());
197 println!("v {:?}", v);
198 assert!(v);
199
200 let m: Vec<u8> = vec![1, 2, 3, 3];
201 let v = verify(ring, m, key_image, sig);
202 assert!(!v);
203 }
204}