1use crate::signing::{KeyPair, PublicKey, verify as verify_signature};
47use blake3;
48use serde::{Deserialize, Serialize};
49use thiserror::Error;
50
51#[derive(Debug, Error)]
53pub enum LinkableRingError {
54 #[error("Ring must contain at least 2 public keys")]
55 RingTooSmall,
56
57 #[error("Signer not found in ring")]
58 SignerNotInRing,
59
60 #[error("Invalid signature")]
61 InvalidSignature,
62
63 #[error("Serialization error: {0}")]
64 SerializationError(String),
65
66 #[error("Ring size mismatch")]
67 RingSizeMismatch,
68
69 #[error("Invalid key image")]
70 InvalidKeyImage,
71}
72
73pub type LinkableRingResult<T> = Result<T, LinkableRingError>;
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
81pub struct LinkableRingSignature {
82 commitments: Vec<[u8; 32]>,
84 #[serde(with = "serde_signature")]
86 signature: [u8; 64],
87 key_image: [u8; 32],
89 ring_hash: [u8; 32],
91}
92
93mod serde_signature {
95 use serde::{Deserialize, Deserializer, Serializer};
96
97 pub fn serialize<S>(bytes: &[u8; 64], serializer: S) -> Result<S::Ok, S::Error>
98 where
99 S: Serializer,
100 {
101 serializer.serialize_bytes(bytes)
102 }
103
104 pub fn deserialize<'de, D>(deserializer: D) -> Result<[u8; 64], D::Error>
105 where
106 D: Deserializer<'de>,
107 {
108 let bytes: Vec<u8> = Deserialize::deserialize(deserializer)?;
109 if bytes.len() != 64 {
110 return Err(serde::de::Error::custom("invalid signature length"));
111 }
112 let mut array = [0u8; 64];
113 array.copy_from_slice(&bytes);
114 Ok(array)
115 }
116}
117
118impl LinkableRingSignature {
119 pub fn to_bytes(&self) -> LinkableRingResult<Vec<u8>> {
121 crate::codec::encode(self).map_err(|e| LinkableRingError::SerializationError(e.to_string()))
122 }
123
124 pub fn from_bytes(bytes: &[u8]) -> LinkableRingResult<Self> {
126 crate::codec::decode(bytes)
127 .map_err(|e| LinkableRingError::SerializationError(e.to_string()))
128 }
129
130 pub fn key_image(&self) -> &[u8; 32] {
132 &self.key_image
133 }
134
135 pub fn ring_hash(&self) -> &[u8; 32] {
137 &self.ring_hash
138 }
139
140 pub fn ring_size(&self) -> usize {
142 self.commitments.len()
143 }
144}
145
146fn compute_key_image(secret_key: &[u8; 32], ring_hash: &[u8; 32]) -> [u8; 32] {
152 let mut hasher = blake3::Hasher::new();
153 hasher.update(b"CHIE-KEY-IMAGE-V1");
154 hasher.update(secret_key);
155 hasher.update(ring_hash);
156 *hasher.finalize().as_bytes()
157}
158
159fn compute_ring_hash(ring: &[PublicKey]) -> [u8; 32] {
161 let mut hasher = blake3::Hasher::new();
162 hasher.update(b"CHIE-RING-HASH-V1");
163 for pk in ring {
164 hasher.update(pk);
165 }
166 *hasher.finalize().as_bytes()
167}
168
169pub fn sign_linkable(
175 signer: &KeyPair,
176 ring: &[PublicKey],
177 message: &[u8],
178) -> LinkableRingResult<LinkableRingSignature> {
179 if ring.len() < 2 {
180 return Err(LinkableRingError::RingTooSmall);
181 }
182
183 let signer_pubkey = signer.public_key();
185 let _signer_index = ring
186 .iter()
187 .position(|pk| pk == &signer_pubkey)
188 .ok_or(LinkableRingError::SignerNotInRing)?;
189
190 let ring_hash = compute_ring_hash(ring);
192
193 let secret_key = signer.secret_key();
195 let key_image = compute_key_image(&secret_key, &ring_hash);
196
197 let mut commitments = Vec::with_capacity(ring.len());
199
200 for (i, pk) in ring.iter().enumerate() {
201 let mut hasher = blake3::Hasher::new();
202 hasher.update(b"CHIE-LINKABLE-RING-V1");
203 hasher.update(message);
204 hasher.update(pk);
205 hasher.update(&i.to_le_bytes());
206 hasher.update(&ring_hash);
207 hasher.update(&key_image);
208
209 for ring_pk in ring {
210 hasher.update(ring_pk);
211 }
212
213 commitments.push(*hasher.finalize().as_bytes());
214 }
215
216 let mut sig_message = Vec::new();
218 sig_message.extend_from_slice(message);
219 sig_message.extend_from_slice(&key_image);
220 sig_message.extend_from_slice(&ring_hash);
221 for commitment in &commitments {
222 sig_message.extend_from_slice(commitment);
223 }
224
225 let signature = signer.sign(&sig_message);
226
227 Ok(LinkableRingSignature {
228 commitments,
229 signature,
230 key_image,
231 ring_hash,
232 })
233}
234
235pub fn verify_linkable(
240 ring: &[PublicKey],
241 message: &[u8],
242 signature: &LinkableRingSignature,
243) -> LinkableRingResult<bool> {
244 if ring.len() < 2 {
245 return Err(LinkableRingError::RingTooSmall);
246 }
247
248 if ring.len() != signature.commitments.len() {
249 return Err(LinkableRingError::RingSizeMismatch);
250 }
251
252 let expected_ring_hash = compute_ring_hash(ring);
254 if expected_ring_hash != signature.ring_hash {
255 return Ok(false);
256 }
257
258 for (i, pk) in ring.iter().enumerate() {
260 let mut hasher = blake3::Hasher::new();
261 hasher.update(b"CHIE-LINKABLE-RING-V1");
262 hasher.update(message);
263 hasher.update(pk);
264 hasher.update(&i.to_le_bytes());
265 hasher.update(&signature.ring_hash);
266 hasher.update(&signature.key_image);
267
268 for ring_pk in ring {
269 hasher.update(ring_pk);
270 }
271
272 let expected_commitment = hasher.finalize();
273 if expected_commitment.as_bytes() != &signature.commitments[i] {
274 return Ok(false);
275 }
276 }
277
278 let mut sig_message = Vec::new();
280 sig_message.extend_from_slice(message);
281 sig_message.extend_from_slice(&signature.key_image);
282 sig_message.extend_from_slice(&signature.ring_hash);
283 for commitment in &signature.commitments {
284 sig_message.extend_from_slice(commitment);
285 }
286
287 for pk in ring {
288 if verify_signature(pk, &sig_message, &signature.signature).is_ok() {
289 return Ok(true);
290 }
291 }
292
293 Ok(false)
294}
295
296pub fn check_double_sign(sig1: &LinkableRingSignature, sig2: &LinkableRingSignature) -> bool {
301 sig1.key_image == sig2.key_image && sig1.ring_hash == sig2.ring_hash
302}
303
304pub struct KeyImageDb {
306 used_images: std::collections::HashSet<Vec<u8>>,
308}
309
310impl KeyImageDb {
311 pub fn new() -> Self {
313 Self {
314 used_images: std::collections::HashSet::new(),
315 }
316 }
317
318 pub fn is_used(&self, signature: &LinkableRingSignature) -> bool {
320 let mut key = Vec::new();
321 key.extend_from_slice(&signature.ring_hash);
322 key.extend_from_slice(&signature.key_image);
323 self.used_images.contains(&key)
324 }
325
326 pub fn mark_used(&mut self, signature: &LinkableRingSignature) -> bool {
330 let mut key = Vec::new();
331 key.extend_from_slice(&signature.ring_hash);
332 key.extend_from_slice(&signature.key_image);
333 self.used_images.insert(key)
334 }
335
336 pub fn size(&self) -> usize {
338 self.used_images.len()
339 }
340
341 pub fn clear(&mut self) {
343 self.used_images.clear();
344 }
345}
346
347impl Default for KeyImageDb {
348 fn default() -> Self {
349 Self::new()
350 }
351}
352
353#[cfg(test)]
354mod tests {
355 use super::*;
356 use crate::signing::KeyPair;
357
358 #[test]
359 fn test_linkable_ring_basic() {
360 let keypair1 = KeyPair::generate();
361 let keypair2 = KeyPair::generate();
362 let keypair3 = KeyPair::generate();
363
364 let ring = vec![
365 keypair1.public_key(),
366 keypair2.public_key(),
367 keypair3.public_key(),
368 ];
369
370 let message = b"Test message";
371 let signature = sign_linkable(&keypair2, &ring, message).unwrap();
372
373 assert!(verify_linkable(&ring, message, &signature).unwrap());
374 }
375
376 #[test]
377 fn test_double_sign_detection() {
378 let keypair1 = KeyPair::generate();
379 let keypair2 = KeyPair::generate();
380 let keypair3 = KeyPair::generate();
381
382 let ring = vec![
383 keypair1.public_key(),
384 keypair2.public_key(),
385 keypair3.public_key(),
386 ];
387
388 let msg1 = b"Transaction 1";
390 let msg2 = b"Transaction 2";
391
392 let sig1 = sign_linkable(&keypair2, &ring, msg1).unwrap();
393 let sig2 = sign_linkable(&keypair2, &ring, msg2).unwrap();
394
395 assert!(check_double_sign(&sig1, &sig2));
397 assert_eq!(sig1.key_image(), sig2.key_image());
398 }
399
400 #[test]
401 fn test_different_signers_different_images() {
402 let keypair1 = KeyPair::generate();
403 let keypair2 = KeyPair::generate();
404 let keypair3 = KeyPair::generate();
405
406 let ring = vec![
407 keypair1.public_key(),
408 keypair2.public_key(),
409 keypair3.public_key(),
410 ];
411
412 let message = b"Same message";
413
414 let sig1 = sign_linkable(&keypair1, &ring, message).unwrap();
415 let sig2 = sign_linkable(&keypair2, &ring, message).unwrap();
416
417 assert!(!check_double_sign(&sig1, &sig2));
419 assert_ne!(sig1.key_image(), sig2.key_image());
420 }
421
422 #[test]
423 fn test_different_rings_different_images() {
424 let keypair1 = KeyPair::generate();
425 let keypair2 = KeyPair::generate();
426 let keypair3 = KeyPair::generate();
427 let keypair4 = KeyPair::generate();
428
429 let ring1 = vec![
430 keypair1.public_key(),
431 keypair2.public_key(),
432 keypair3.public_key(),
433 ];
434
435 let ring2 = vec![
436 keypair1.public_key(),
437 keypair2.public_key(),
438 keypair4.public_key(),
439 ];
440
441 let message = b"Test";
442
443 let sig1 = sign_linkable(&keypair1, &ring1, message).unwrap();
445 let sig2 = sign_linkable(&keypair1, &ring2, message).unwrap();
446
447 assert!(!check_double_sign(&sig1, &sig2));
449 assert_ne!(sig1.key_image(), sig2.key_image());
450 assert_ne!(sig1.ring_hash(), sig2.ring_hash());
451 }
452
453 #[test]
454 fn test_serialization() {
455 let keypair1 = KeyPair::generate();
456 let keypair2 = KeyPair::generate();
457
458 let ring = vec![keypair1.public_key(), keypair2.public_key()];
459 let message = b"Serialization test";
460
461 let signature = sign_linkable(&keypair1, &ring, message).unwrap();
462
463 let bytes = signature.to_bytes().unwrap();
464 let deserialized = LinkableRingSignature::from_bytes(&bytes).unwrap();
465
466 assert!(verify_linkable(&ring, message, &deserialized).unwrap());
467 assert_eq!(signature.key_image(), deserialized.key_image());
468 }
469
470 #[test]
471 fn test_key_image_db() {
472 let keypair1 = KeyPair::generate();
473 let keypair2 = KeyPair::generate();
474
475 let ring = vec![keypair1.public_key(), keypair2.public_key()];
476
477 let msg1 = b"Transaction 1";
478 let msg2 = b"Transaction 2";
479
480 let sig1 = sign_linkable(&keypair1, &ring, msg1).unwrap();
481 let sig2 = sign_linkable(&keypair1, &ring, msg2).unwrap();
482
483 let mut db = KeyImageDb::new();
484
485 assert!(db.mark_used(&sig1));
487 assert_eq!(db.size(), 1);
488
489 assert!(db.is_used(&sig1));
491
492 assert!(!db.mark_used(&sig2));
494
495 let sig3 = sign_linkable(&keypair2, &ring, msg1).unwrap();
497 assert!(db.mark_used(&sig3));
498 assert_eq!(db.size(), 2);
499 }
500
501 #[test]
502 fn test_wrong_message() {
503 let keypair1 = KeyPair::generate();
504 let keypair2 = KeyPair::generate();
505
506 let ring = vec![keypair1.public_key(), keypair2.public_key()];
507
508 let message = b"Original";
509 let wrong_message = b"Wrong";
510
511 let signature = sign_linkable(&keypair1, &ring, message).unwrap();
512
513 assert!(!verify_linkable(&ring, wrong_message, &signature).unwrap());
514 }
515
516 #[test]
517 fn test_ring_too_small() {
518 let keypair = KeyPair::generate();
519 let ring = vec![keypair.public_key()];
520 let message = b"Test";
521
522 let result = sign_linkable(&keypair, &ring, message);
523 assert!(matches!(result, Err(LinkableRingError::RingTooSmall)));
524 }
525
526 #[test]
527 fn test_signer_not_in_ring() {
528 let keypair1 = KeyPair::generate();
529 let keypair2 = KeyPair::generate();
530 let outsider = KeyPair::generate();
531
532 let ring = vec![keypair1.public_key(), keypair2.public_key()];
533 let message = b"Test";
534
535 let result = sign_linkable(&outsider, &ring, message);
536 assert!(matches!(result, Err(LinkableRingError::SignerNotInRing)));
537 }
538}