diff --git a/plonky2/src/curve/ecdsa.rs b/plonky2/src/curve/ecdsa.rs index 177f08ed..0ed777d9 100644 --- a/plonky2/src/curve/ecdsa.rs +++ b/plonky2/src/curve/ecdsa.rs @@ -1,5 +1,3 @@ -use std::ops::Mul; - use itertools::unfold; use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar}; @@ -11,8 +9,8 @@ pub struct ECDSASignature { pub s: C::ScalarField, } -pub struct ECDSASecretKey(C::ScalarField); -pub struct ECDSAPublicKey(AffinePoint); +pub struct ECDSASecretKey(pub C::ScalarField); +pub struct ECDSAPublicKey(pub AffinePoint); pub fn base_to_scalar(x: C::BaseField) -> C::ScalarField { C::ScalarField::from_biguint(x.to_biguint()) @@ -22,15 +20,6 @@ pub fn scalar_to_base(x: C::ScalarField) -> C::BaseField { C::BaseField::from_biguint(x.to_biguint()) } -pub fn hash_to_scalar(msg: F, num_bits: usize) -> C::ScalarField { - let h_bits = hash_to_bits(msg, num_bits); - let h_u32 = h_bits - .iter() - .zip(0..32) - .fold(0u32, |acc, (&bit, pow)| acc + (bit as u32) * (2 << pow)); - C::ScalarField::from_canonical_u32(h_u32) -} - pub fn hash_to_bits(x: F, num_bits: usize) -> Vec { let hashed = hash_n_to_1(vec![x], true); @@ -44,6 +33,15 @@ pub fn hash_to_bits(x: F, num_bits: usize) -> Vec { .collect() } +pub fn hash_to_scalar(x: F, num_bits: usize) -> C::ScalarField { + let h_bits = hash_to_bits(x, num_bits); + let h_u32 = h_bits + .iter() + .zip(0..32) + .fold(0u32, |acc, (&bit, pow)| acc + (bit as u32) * (2 << pow)); + C::ScalarField::from_canonical_u32(h_u32) +} + pub fn sign_message(msg: F, sk: ECDSASecretKey) -> ECDSASignature { let h = hash_to_scalar::(msg, 32); @@ -76,16 +74,14 @@ pub fn verify_message( r == x } +#[cfg(test)] mod tests { - use anyhow::Result; - use crate::curve::curve_types::{Curve, CurveScalar}; use crate::curve::ecdsa::{sign_message, verify_message, ECDSAPublicKey, ECDSASecretKey}; use crate::curve::secp256k1::Secp256K1; use crate::field::field_types::Field; use crate::field::goldilocks_field::GoldilocksField; use crate::field::secp256k1_scalar::Secp256K1Scalar; - use crate::plonk::circuit_data::CircuitConfig; #[test] fn test_ecdsa_native() { diff --git a/plonky2/src/gadgets/nonnative.rs b/plonky2/src/gadgets/nonnative.rs index 16fd022e..824d851c 100644 --- a/plonky2/src/gadgets/nonnative.rs +++ b/plonky2/src/gadgets/nonnative.rs @@ -15,7 +15,7 @@ use crate::plonk::circuit_builder::CircuitBuilder; #[derive(Clone, Debug)] pub struct NonNativeTarget { pub(crate) value: BigUintTarget, - _phantom: PhantomData, + pub(crate) _phantom: PhantomData, } impl, const D: usize> CircuitBuilder { diff --git a/waksman/src/ecdsa.rs b/waksman/src/ecdsa.rs index 47068ee8..199a8c56 100644 --- a/waksman/src/ecdsa.rs +++ b/waksman/src/ecdsa.rs @@ -1,3 +1,15 @@ +use std::marker::PhantomData; + +use crate::curve::curve_types::Curve; +use crate::field::extension_field::Extendable; +use crate::field::field_types::RichField; +use crate::gadgets::arithmetic_u32::U32Target; +use crate::gadgets::biguint::BigUintTarget; +use crate::gadgets::curve::AffinePointTarget; +use crate::gadgets::nonnative::NonNativeTarget; +use crate::iop::target::{BoolTarget, Target}; +use crate::plonk::circuit_builder::CircuitBuilder; + pub struct ECDSASecretKeyTarget(NonNativeTarget); pub struct ECDSAPublicKeyTarget(AffinePointTarget); @@ -6,48 +18,105 @@ pub struct ECDSASignatureTarget { pub s: NonNativeTarget, } - - impl, const D: usize> CircuitBuilder { - + pub fn hash_to_bits(&mut self, x: Target, num_bits: usize) -> Vec { + let inputs = vec![x]; + let hashed = self.hash_n_to_m(inputs, 1, true)[0]; + self.split_le(hashed, num_bits) + } + + pub fn hash_to_scalar(&mut self, x: Target, num_bits: usize) -> NonNativeTarget { + let h_bits = self.hash_to_bits(x, num_bits); + + let two = self.two(); + let mut rev_bits = h_bits.iter().rev(); + let mut sum = rev_bits.next().unwrap().target; + for &bit in rev_bits { + sum = self.mul_add(two, sum, bit.target); + } + let limbs = vec![U32Target(sum)]; + let value = BigUintTarget { + limbs, + }; + + NonNativeTarget { + value, + _phantom: PhantomData, + } + } + + pub fn verify_message(&mut self, msg: Target, sig: ECDSASignatureTarget, pk: ECDSAPublicKeyTarget) { + let ECDSASignatureTarget { r, s } = sig; + + let h = self.hash_to_scalar::(msg, 32); + + let c = self.inv_nonnative(&s); + let u1 = self.mul_nonnative(&h, &c); + let u2 = self.mul_nonnative(&r, &c); + + let g = self.constant_affine_point(C::GENERATOR_AFFINE); + let point1 = self.curve_scalar_mul(&g, &u1); + let point2 = self.curve_scalar_mul(&pk.0, &u2); + let point = self.curve_add(&point1, &point2); + + let x = NonNativeTarget:: { + value: point.x.value, + _phantom: PhantomData, + }; + self.connect_nonnative(&r, &x); + } } +#[cfg(test)] mod tests { - use std::ops::{Mul, Neg}; - use anyhow::Result; - use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar}; + use crate::curve::curve_types::{Curve, CurveScalar}; + use crate::curve::ecdsa::{ECDSAPublicKey, ECDSASecretKey, ECDSASignature, sign_message}; use crate::curve::secp256k1::Secp256K1; use crate::field::field_types::Field; use crate::field::goldilocks_field::GoldilocksField; - use crate::field::secp256k1_base::Secp256K1Base; use crate::field::secp256k1_scalar::Secp256K1Scalar; + use crate::gadgets::ecdsa::{ECDSAPublicKeyTarget, ECDSASignatureTarget}; use crate::iop::witness::PartialWitness; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; use crate::plonk::verifier::verify; - /*#[test] - fn test_curve_point_is_valid() -> Result<()> { + #[test] + fn test_ecdsa_circuit() -> Result<()> { type F = GoldilocksField; const D: usize = 4; + type C = Secp256K1; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); let mut builder = CircuitBuilder::::new(config); - let g = Secp256K1::GENERATOR_AFFINE; - let g_target = builder.constant_affine_point(g); - let neg_g_target = builder.curve_neg(&g_target); + let msg = F::rand(); + let msg_target = builder.constant(msg); + + let sk = ECDSASecretKey::(Secp256K1Scalar::rand()); + let pk = ECDSAPublicKey((CurveScalar(sk.0) * C::GENERATOR_PROJECTIVE).to_affine()); - builder.curve_assert_valid(&g_target); - builder.curve_assert_valid(&neg_g_target); + let pk_target = ECDSAPublicKeyTarget(builder.constant_affine_point(pk.0)); + + let sig = sign_message(msg, sk); + + let ECDSASignature { r, s } = sig; + let r_target = builder.constant_nonnative(r); + let s_target = builder.constant_nonnative(s); + let sig_target = ECDSASignatureTarget { + r: r_target, + s: s_target, + }; + + builder.verify_message(msg_target, sig_target, pk_target); let data = builder.build(); let proof = data.prove(pw).unwrap(); verify(proof, &data.verifier_only, &data.common) - }*/ + } }