add circuit to verify signatures (SignatureVerifyGadget) (#167)

* implement circuit to verify signature (proof-based signature), ie. a 1-level recursion verification

* as agreed in the call, rename Gate -> Gadget when it's not a 'gate'

* make SignatureVerifyGadget conditional on the selector input

* small naming polish

* sigverifygadget: add s computation in-circuit, connect pk,msg,s to internalproof's public_inputs

* optimize signature verify

---------

Co-authored-by: Eduard S. <eduardsanou@posteo.net>
This commit is contained in:
arnaucube 2025-04-01 01:36:37 +02:00 committed by GitHub
parent d00ff95f41
commit 0637f52573
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 325 additions and 42 deletions

View file

@ -1,6 +1,7 @@
//! Proof-based signatures using Plonky2 proofs, following
//! https://eprint.iacr.org/2024/1553 .
use anyhow::Result;
use lazy_static::lazy_static;
use plonky2::{
field::types::Sample,
hash::{
@ -21,23 +22,31 @@ use plonky2::{
use crate::backends::plonky2::basetypes::{Proof, Value, C, D, F, VALUE_SIZE};
use lazy_static::lazy_static;
pub use super::signature_circuit::*;
lazy_static! {
static ref PP: ProverParams = Signature::prover_params().unwrap();
static ref VP: VerifierParams = Signature::verifier_params().unwrap();
/// Signature prover parameters
pub static ref PP: ProverParams = Signature::prover_params().unwrap();
/// Signature verifier parameters
pub static ref VP: VerifierParams = Signature::verifier_params().unwrap();
/// DUMMY_SIGNATURE is used for conditionals where we want to use a `selector` to enable or
/// disable signature verification.
pub static ref DUMMY_SIGNATURE: Signature = dummy_signature().unwrap();
/// DUMMY_PUBLIC_INPUTS accompanies the DUMMY_SIGNATURE.
pub static ref DUMMY_PUBLIC_INPUTS: Vec<F> = dummy_public_inputs().unwrap();
}
pub struct ProverParams {
prover: ProverCircuitData<F, C, D>,
circuit: SignatureCircuit,
circuit: SignatureInternalCircuit,
}
#[derive(Clone, Debug)]
pub struct VerifierParams(VerifierCircuitData<F, C, D>);
pub struct VerifierParams(pub(crate) VerifierCircuitData<F, C, D>);
#[derive(Clone, Debug)]
pub struct SecretKey(Value);
pub struct SecretKey(pub(crate) Value);
#[derive(Clone, Debug)]
pub struct PublicKey(pub(crate) Value);
@ -90,12 +99,12 @@ impl Signature {
Ok((pp, vp))
}
fn builder() -> Result<(CircuitBuilder<F, D>, SignatureCircuit)> {
fn builder() -> Result<(CircuitBuilder<F, D>, SignatureInternalCircuit)> {
// notice that we use the 'zk' config
let config = CircuitConfig::standard_recursion_zk_config();
let mut builder = CircuitBuilder::<F, D>::new(config);
let circuit = SignatureCircuit::add_targets(&mut builder)?;
let circuit = SignatureInternalCircuit::add_targets(&mut builder)?;
Ok((builder, circuit))
}
@ -113,21 +122,35 @@ impl Signature {
}
}
/// The SignatureCircuit implements the circuit used for the proof of the
/// argument described at https://eprint.iacr.org/2024/1553.
fn dummy_public_inputs() -> Result<Vec<F>> {
let sk = SecretKey(Value::from(0));
let pk = sk.public_key();
let msg = Value::from(0);
let s = Value(PoseidonHash::hash_no_pad(&[pk.0 .0, msg.0].concat()).elements);
Ok([pk.0 .0, msg.0, s.0].concat())
}
fn dummy_signature() -> Result<Signature> {
let sk = SecretKey(Value::from(0));
let msg = Value::from(0);
sk.sign(msg)
}
/// The SignatureInternalCircuit implements the circuit used for the proof of
/// the argument described at https://eprint.iacr.org/2024/1553.
///
/// The circuit proves that for the given public inputs (pk, msg, s), the Prover
/// knows the secret (sk) such that:
/// i) pk == H(sk)
/// ii) s == H(pk, msg)
struct SignatureCircuit {
struct SignatureInternalCircuit {
sk_targ: Vec<Target>,
pk_targ: HashOutTarget,
msg_targ: Vec<Target>,
s_targ: HashOutTarget,
}
impl SignatureCircuit {
impl SignatureInternalCircuit {
/// creates the targets and defines the logic of the circuit
fn add_targets(builder: &mut CircuitBuilder<F, D>) -> Result<Self> {
// create the targets
@ -182,7 +205,6 @@ pub mod tests {
use super::*;
// Note: this test must be run with the `--release` flag.
#[test]
fn test_signature() -> Result<()> {
let sk = SecretKey::new();
@ -203,4 +225,14 @@ pub mod tests {
Ok(())
}
#[test]
fn test_dummy_signature() -> Result<()> {
let sk = SecretKey(Value::from(0));
let pk = sk.public_key();
let msg = Value::from(0);
DUMMY_SIGNATURE.clone().verify(&pk, msg)?;
Ok(())
}
}