jf_signature/
lib.rs

1// Copyright (c) 2022 Espresso Systems (espressosys.com)
2// This file is part of the Jellyfish library.
3
4// You should have received a copy of the MIT License
5// along with the Jellyfish library. If not, see <https://mit-license.org/>.
6//! Module for signature primitives.
7
8#![cfg_attr(not(feature = "std"), no_std)]
9// Temporarily allow warning for nightly compilation with [`displaydoc`].
10#![allow(warnings)]
11#![deny(missing_docs)]
12#[cfg(test)]
13extern crate std;
14
15#[cfg(any(test, feature = "schnorr"))]
16#[macro_use]
17extern crate derivative;
18
19#[cfg(any(not(feature = "std"), target_has_atomic = "ptr"))]
20#[doc(hidden)]
21extern crate alloc;
22
23use ark_std::rand::{CryptoRng, RngCore};
24
25#[cfg(any(test, feature = "bls"))]
26pub mod bls_over_bls12381;
27#[cfg(any(test, feature = "bls"))]
28pub mod bls_over_bn254;
29pub mod constants;
30#[cfg(feature = "gadgets")]
31pub mod gadgets;
32#[cfg(any(test, feature = "schnorr"))]
33pub mod schnorr;
34
35use ark_std::{
36    format,
37    string::{String, ToString},
38};
39use blst::BLST_ERROR;
40use core::fmt::Debug;
41use displaydoc::Display;
42use serde::{Deserialize, Serialize};
43use zeroize::Zeroize;
44
45/// Signature error type
46#[derive(Debug, Display, Eq, PartialEq)]
47pub enum SignatureError {
48    /// Bad parameter in function call, {0}
49    ParameterError(String),
50    /// Value is not in the right subgroup
51    FailedSubgroupCheck,
52    /// Value is not on the right elliptic curve
53    FailedOnCurveCheck,
54    // union over `FailedSubgroupCheck` and `FailedOnCurveCheck`
55    /// Value is not valid (possible cause: not on curve, in wrong subgroup,)
56    FailedValidityCheck,
57    /// Verification failed, {0}
58    VerificationError(String),
59}
60
61impl ark_std::error::Error for SignatureError {}
62
63impl From<BLST_ERROR> for SignatureError {
64    fn from(e: BLST_ERROR) -> Self {
65        match e {
66            BLST_ERROR::BLST_SUCCESS => {
67                Self::ParameterError("Expecting an error, but got a success.".to_string())
68            },
69            BLST_ERROR::BLST_VERIFY_FAIL => Self::VerificationError(format!("{e:?}")),
70            _ => Self::ParameterError(format!("{e:?}")),
71        }
72    }
73}
74
75/// Trait definition for a signature scheme.
76// A signature scheme is associated with a hash function H that is
77// to be used for challenge generation.
78// FIXME: update H bound once hash-api is merged.
79pub trait SignatureScheme: Clone + Send + Sync + 'static {
80    /// Ciphersuite Identifier
81    const CS_ID: &'static str;
82
83    /// Signing key.
84    type SigningKey: Debug + Clone + Send + Sync + Zeroize + PartialEq + Eq;
85
86    /// Verification key
87    type VerificationKey: Debug
88        + Clone
89        + Send
90        + Sync
91        + for<'a> Deserialize<'a>
92        + Serialize
93        + PartialEq
94        + Eq;
95
96    /// Public Parameter
97    type PublicParameter: Debug + Clone + PartialEq + for<'a> Deserialize<'a> + Serialize;
98
99    /// Signature
100    type Signature: Debug
101        + Clone
102        + Send
103        + Sync
104        + for<'a> Deserialize<'a>
105        + Serialize
106        + PartialEq
107        + Eq;
108
109    /// A message is &\[MessageUnit\]
110    type MessageUnit: Debug + Clone + Send + Sync;
111
112    /// generate public parameters from RNG.
113    /// If the RNG is not presented, use the default group generator.
114    // FIXME: the API looks a bit strange when the default generator is used.
115    // For example:
116    //   `S::param_gen::<StdRng>(None)`
117    // where `StdRng` is redundant.
118    fn param_gen<R: CryptoRng + RngCore>(
119        prng: Option<&mut R>,
120    ) -> Result<Self::PublicParameter, SignatureError>;
121
122    /// Sample a pair of keys.
123    fn key_gen<R: CryptoRng + RngCore>(
124        pp: &Self::PublicParameter,
125        prng: &mut R,
126    ) -> Result<(Self::SigningKey, Self::VerificationKey), SignatureError>;
127
128    /// Sign a message with the signing key
129    fn sign<R: CryptoRng + RngCore, M: AsRef<[Self::MessageUnit]>>(
130        pp: &Self::PublicParameter,
131        sk: &Self::SigningKey,
132        msg: M,
133        prng: &mut R,
134    ) -> Result<Self::Signature, SignatureError>;
135
136    /// Verify a signature.
137    fn verify<M: AsRef<[Self::MessageUnit]>>(
138        pp: &Self::PublicParameter,
139        vk: &Self::VerificationKey,
140        msg: M,
141        sig: &Self::Signature,
142    ) -> Result<(), SignatureError>;
143}
144
145/// Trait for aggregatable signatures.
146/// TODO: generic over hash functions
147// NOTE: we +Debug here instead of on `SignatureSchemes` because `schnorr <P:
148// CurveConfig>` doesn't impl Debug
149pub trait AggregateableSignatureSchemes:
150    SignatureScheme + Serialize + for<'a> Deserialize<'a> + Debug
151{
152    /// Aggregate multiple signatures into a single signature
153    /// The list of public keys is also in the input as some aggregate signature
154    /// schemes might also use pks for aggregation
155    fn aggregate(
156        pp: &Self::PublicParameter,
157        vks: &[Self::VerificationKey],
158        sigs: &[Self::Signature],
159    ) -> Result<Self::Signature, SignatureError>;
160
161    /// Verify an aggregate signature w.r.t. a list of messages and public keys.
162    /// It is user's responsibility to ensure that the public keys are
163    /// validated.
164    fn aggregate_verify<M: AsRef<[Self::MessageUnit]>>(
165        pp: &Self::PublicParameter,
166        vks: &[Self::VerificationKey],
167        msgs: &[M],
168        sig: &Self::Signature,
169    ) -> Result<(), SignatureError>;
170
171    /// Verify a multisignature w.r.t. a single message and a list of public
172    /// keys. It is user's responsibility to ensure that the public keys are
173    /// validated.
174    fn multi_sig_verify(
175        pp: &Self::PublicParameter,
176        vks: &[Self::VerificationKey],
177        msg: &[Self::MessageUnit],
178        sig: &Self::Signature,
179    ) -> Result<(), SignatureError>;
180}
181
182#[cfg(test)]
183mod tests {
184    use super::*;
185    use ark_std::{rand::prelude::StdRng, vec, vec::Vec};
186    use jf_utils::test_rng;
187
188    pub(crate) fn sign_and_verify<S: SignatureScheme>(message: &[S::MessageUnit]) {
189        let rng = &mut test_rng();
190        let parameters = S::param_gen(Some(rng)).unwrap();
191        let (sk, pk) = S::key_gen(&parameters, rng).unwrap();
192        let sig = S::sign(&parameters, &sk, message, rng).unwrap();
193        assert!(S::verify(&parameters, &pk, message, &sig).is_ok());
194
195        let parameters = S::param_gen::<StdRng>(None).unwrap();
196        let (sk, pk) = S::key_gen(&parameters, rng).unwrap();
197        let sig = S::sign(&parameters, &sk, message, rng).unwrap();
198        assert!(S::verify(&parameters, &pk, message, &sig).is_ok());
199    }
200
201    pub(crate) fn agg_sign_and_verify<S: AggregateableSignatureSchemes>(
202        messages: &[&[S::MessageUnit]],
203        bad_message: &[S::MessageUnit],
204    ) {
205        let rng = &mut test_rng();
206        let parameters = S::param_gen(Some(rng)).unwrap();
207        let mut pks = vec![];
208        let mut sigs = vec![];
209        let mut partial_sigs = vec![];
210        let message_for_msig = messages[0];
211        for message in messages.iter() {
212            let (sk, pk) = S::key_gen(&parameters, rng).unwrap();
213            let sig = S::sign(&parameters, &sk, message, rng).unwrap();
214            let partial_sig = S::sign(&parameters, &sk, message_for_msig, rng).unwrap();
215            pks.push(pk);
216            sigs.push(sig);
217            partial_sigs.push(partial_sig);
218        }
219        // happy paths
220        let agg_sig = S::aggregate(&parameters, &pks, &sigs).unwrap();
221        let multi_sig = S::aggregate(&parameters, &pks, &partial_sigs).unwrap();
222        assert!(S::aggregate_verify(&parameters, &pks, messages, &agg_sig).is_ok());
223        assert!(S::multi_sig_verify(&parameters, &pks, message_for_msig, &multi_sig).is_ok());
224        // wrong messages length
225        assert!(S::aggregate_verify(&parameters, &pks, &messages[1..], &agg_sig).is_err());
226        // empty pks
227        assert!(S::aggregate_verify(&parameters, &[], messages, &agg_sig).is_err());
228        assert!(S::multi_sig_verify(&parameters, &[], message_for_msig, &multi_sig).is_err());
229        // wrong message
230        let mut bad_messages: Vec<&[S::MessageUnit]> = messages.to_vec();
231        bad_messages[0] = bad_message;
232        assert!(S::aggregate_verify(&parameters, &pks, &bad_messages, &agg_sig).is_err());
233        assert!(S::multi_sig_verify(&parameters, &pks, bad_message, &multi_sig).is_err());
234    }
235
236    pub(crate) fn failed_verification<S: SignatureScheme>(
237        message: &[S::MessageUnit],
238        bad_message: &[S::MessageUnit],
239    ) {
240        let rng = &mut test_rng();
241        let parameters = S::param_gen(Some(rng)).unwrap();
242        let (sk, pk) = S::key_gen(&parameters, rng).unwrap();
243        let sig = S::sign(&parameters, &sk, message, rng).unwrap();
244        assert!(S::verify(&parameters, &pk, bad_message, &sig).is_err());
245    }
246}