cuprate_consensus_rules/transactions/
ring_signatures.rs

1//! Version 1 ring signature verification.
2//!
3//! Some checks have to be done at deserialization or with data we don't have so we can't do them here, those checks are:
4//! <https://monero-book.cuprate.org/consensus_rules/transactions/ring_signatures.html#signatures-must-be-canonical>
5//! this happens at deserialization in monero-serai.
6//! <https://monero-book.cuprate.org/consensus_rules/transactions/ring_signatures.html#amount-of-signatures-in-a-ring>
7//! and this happens during ring signature verification in monero-serai.
8//!
9use monero_serai::{ring_signatures::RingSignature, transaction::Input};
10
11#[cfg(feature = "rayon")]
12use rayon::prelude::*;
13
14use super::{Rings, TransactionError};
15use crate::try_par_iter;
16
17/// Verifies the ring signature.
18///
19/// ref: <https://monero-book.cuprate.org/consensus_rules/transactions/ring_signatures.html>
20pub(crate) fn check_input_signatures(
21    inputs: &[Input],
22    signatures: &[RingSignature],
23    rings: &Rings,
24    tx_sig_hash: &[u8; 32],
25) -> Result<(), TransactionError> {
26    match rings {
27        Rings::Legacy(rings) => {
28            // <https://monero-book.cuprate.org/consensus_rules/transactions/ring_signatures.html#amount-of-ring-signatures>
29            // rings.len() != inputs.len() can't happen but check any way.
30            if signatures.len() != inputs.len() || rings.len() != inputs.len() {
31                return Err(TransactionError::RingSignatureIncorrect);
32            }
33
34            try_par_iter(inputs)
35                .zip(rings)
36                .zip(signatures)
37                .try_for_each(|((input, ring), sig)| {
38                    let Input::ToKey { key_image, .. } = input else {
39                        panic!("How did we build a ring with no decoys?");
40                    };
41
42                    if !sig.verify(tx_sig_hash, ring, key_image) {
43                        return Err(TransactionError::RingSignatureIncorrect);
44                    }
45                    Ok(())
46                })?;
47        }
48        Rings::RingCT(_) => panic!("tried to verify v1 tx with a non v1 ring"),
49    }
50    Ok(())
51}