diff --git a/plonky2/src/curve/ecdsa.rs b/plonky2/src/curve/ecdsa.rs new file mode 100644 index 00000000..ca5b27ad --- /dev/null +++ b/plonky2/src/curve/ecdsa.rs @@ -0,0 +1,111 @@ +use std::ops::Mul; + +use itertools::unfold; + +use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar}; +use crate::field::field_types::{Field, RichField}; +use crate::hash::hashing::hash_n_to_1; + +pub struct ECDSASignature { + pub r: C::ScalarField, + pub s: C::ScalarField, +} + +pub struct ECDSASecretKey(C::ScalarField); +pub struct ECDSAPublicKey(AffinePoint); + +pub fn base_to_scalar(x: C::BaseField) -> C::ScalarField { + C::ScalarField::from_biguint(x.to_biguint()) +} + +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); + + let mut val = hashed.to_canonical_u64(); + unfold((), move |_| { + let ret = val % 2 != 0; + val /= 2; + Some(ret) + }) + .take(num_bits) + .collect() +} + +pub fn sign_message(msg: F, sk: ECDSASecretKey) -> ECDSASignature { + let h = hash_to_scalar::(msg, 32); + println!("SIGNING h: {:?}", h); + + let k = C::ScalarField::rand(); + let rr = (CurveScalar(k) * C::GENERATOR_PROJECTIVE).to_affine(); + let r = base_to_scalar::(rr.x); + let s = k.inverse() * (h + r * sk.0); + + println!("SIGNING s: {:?}", s); + println!("SIGNING s^-1: {:?}", s.inverse()); + println!("SIGNING s^-1^-1: {:?}", s.inverse().inverse()); + + ECDSASignature { r, s } +} + +pub fn verify_message( + msg: F, + sig: ECDSASignature, + pk: ECDSAPublicKey, +) -> bool { + let ECDSASignature { r, s } = sig; + + let h = hash_to_scalar::(msg, 32); + println!("VERIFYING h: {:?}", h); + + let c = s.inverse(); + + println!("VERIFYING c^-1: {:?}", c.inverse()); + let u1 = h * c; + let u2 = r * c; + + let g = C::GENERATOR_PROJECTIVE; + let point_proj = CurveScalar(u1) * g + CurveScalar(u2) * pk.0.to_projective(); + let point = point_proj.to_affine(); + + let x = base_to_scalar::(point.x); + r == x +} + +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() { + type F = GoldilocksField; + type C = Secp256K1; + + let msg = F::rand(); + let sk = ECDSASecretKey(Secp256K1Scalar::rand()); + let pk = ECDSAPublicKey((CurveScalar(sk.0) * C::GENERATOR_PROJECTIVE).to_affine()); + + let sig = sign_message(msg, sk); + let result = verify_message(msg, sig, pk); + assert!(result); + } +} diff --git a/plonky2/src/curve/mod.rs b/plonky2/src/curve/mod.rs index d31e373e..8dd6f0d6 100644 --- a/plonky2/src/curve/mod.rs +++ b/plonky2/src/curve/mod.rs @@ -3,4 +3,5 @@ pub mod curve_msm; pub mod curve_multiplication; pub mod curve_summation; pub mod curve_types; +pub mod ecdsa; pub mod secp256k1; diff --git a/plonky2/src/gadgets/mod.rs b/plonky2/src/gadgets/mod.rs index b73e2a7f..ec4d1263 100644 --- a/plonky2/src/gadgets/mod.rs +++ b/plonky2/src/gadgets/mod.rs @@ -3,6 +3,7 @@ pub mod arithmetic_extension; pub mod arithmetic_u32; pub mod biguint; pub mod curve; +pub mod ecdsa; pub mod hash; pub mod interpolation; pub mod multiple_comparison; diff --git a/waksman/src/ecdsa.rs b/waksman/src/ecdsa.rs new file mode 100644 index 00000000..47068ee8 --- /dev/null +++ b/waksman/src/ecdsa.rs @@ -0,0 +1,53 @@ +pub struct ECDSASecretKeyTarget(NonNativeTarget); +pub struct ECDSAPublicKeyTarget(AffinePointTarget); + +pub struct ECDSASignatureTarget { + pub r: NonNativeTarget, + pub s: NonNativeTarget, +} + + + +impl, const D: usize> CircuitBuilder { + +} + +mod tests { + use std::ops::{Mul, Neg}; + + use anyhow::Result; + + use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar}; + 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::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<()> { + type F = GoldilocksField; + const D: usize = 4; + + 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); + + builder.curve_assert_valid(&g_target); + builder.curve_assert_valid(&neg_g_target); + + let data = builder.build(); + let proof = data.prove(pw).unwrap(); + + verify(proof, &data.verifier_only, &data.common) + }*/ +}