plonky2-ecdsa/src/gadgets/ecdsa.rs
src/gadgets/ecdsa.rsRaw
1use core::marker::PhantomData;
2
3use plonky2::field::extension::Extendable;
4use plonky2::field::secp256k1_scalar::Secp256K1Scalar;
5use plonky2::hash::hash_types::RichField;
6use plonky2::plonk::circuit_builder::CircuitBuilder;
7
8use crate::curve::curve_types::Curve;
9use crate::curve::secp256k1::Secp256K1;
10use crate::gadgets::curve::{AffinePointTarget, CircuitBuilderCurve};
11use crate::gadgets::curve_fixed_base::fixed_base_curve_mul_circuit;
12use crate::gadgets::glv::CircuitBuilderGlv;
13use crate::gadgets::nonnative::{CircuitBuilderNonNative, NonNativeTarget};
14
15#[derive(Clone, Debug)]
16pub struct ECDSASecretKeyTarget<C: Curve>(pub NonNativeTarget<C::ScalarField>);
17
18#[derive(Clone, Debug)]
19pub struct ECDSAPublicKeyTarget<C: Curve>(pub AffinePointTarget<C>);
20
21#[derive(Clone, Debug)]
22pub struct ECDSASignatureTarget<C: Curve> {
23 pub r: NonNativeTarget<C::ScalarField>,
24 pub s: NonNativeTarget<C::ScalarField>,
25}
26
27pub fn verify_message_circuit<F: RichField + Extendable<D>, const D: usize>(
28 builder: &mut CircuitBuilder<F, D>,
29 msg: NonNativeTarget<Secp256K1Scalar>,
30 sig: ECDSASignatureTarget<Secp256K1>,
31 pk: ECDSAPublicKeyTarget<Secp256K1>,
32) {
33 let ECDSASignatureTarget { r, s } = sig;
34
35 builder.curve_assert_valid(&pk.0);
36
37 let c = builder.inv_nonnative(&s);
38 let u1 = builder.mul_nonnative(&msg, &c);
39 let u2 = builder.mul_nonnative(&r, &c);
40
41 let point1 = fixed_base_curve_mul_circuit(builder, Secp256K1::GENERATOR_AFFINE, &u1);
42 let point2 = builder.glv_mul(&pk.0, &u2);
43 let point = builder.curve_add(&point1, &point2);
44
45 let x = NonNativeTarget::<Secp256K1Scalar> {
46 value: point.x.value,
47 _phantom: PhantomData,
48 };
49 builder.connect_nonnative(&r, &x);
50}
51
52#[cfg(test)]
53mod tests {
54 use anyhow::Result;
55 use plonky2::field::types::Sample;
56 use plonky2::iop::witness::PartialWitness;
57 use plonky2::plonk::circuit_data::CircuitConfig;
58 use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
59
60 use super::*;
61 use crate::curve::curve_types::CurveScalar;
62 use crate::curve::ecdsa::{sign_message, ECDSAPublicKey, ECDSASecretKey, ECDSASignature};
63
64 fn test_ecdsa_circuit_with_config(config: CircuitConfig) -> Result<()> {
65 const D: usize = 2;
66 type C = PoseidonGoldilocksConfig;
67 type F = <C as GenericConfig<D>>::F;
68
69 type Curve = Secp256K1;
70
71 let pw = PartialWitness::new();
72 let mut builder = CircuitBuilder::<F, D>::new(config);
73
74 let msg = Secp256K1Scalar::rand();
75 let msg_target = builder.constant_nonnative(msg);
76
77 let sk = ECDSASecretKey::<Curve>(Secp256K1Scalar::rand());
78 let pk = ECDSAPublicKey((CurveScalar(sk.0) * Curve::GENERATOR_PROJECTIVE).to_affine());
79
80 let pk_target = ECDSAPublicKeyTarget(builder.constant_affine_point(pk.0));
81
82 let sig = sign_message(msg, sk);
83
84 let ECDSASignature { r, s } = sig;
85 let r_target = builder.constant_nonnative(r);
86 let s_target = builder.constant_nonnative(s);
87 let sig_target = ECDSASignatureTarget {
88 r: r_target,
89 s: s_target,
90 };
91
92 verify_message_circuit(&mut builder, msg_target, sig_target, pk_target);
93
94 dbg!(builder.num_gates());
95 let data = builder.build::<C>();
96 let proof = data.prove(pw).unwrap();
97 data.verify(proof)
98 }
99
100 #[test]
101 #[ignore]
102 fn test_ecdsa_circuit_narrow() -> Result<()> {
103 test_ecdsa_circuit_with_config(CircuitConfig::standard_ecc_config())
104 }
105
106 #[test]
107 #[ignore]
108 fn test_ecdsa_circuit_wide() -> Result<()> {
109 test_ecdsa_circuit_with_config(CircuitConfig::wide_ecc_config())
110 }
111}