ECDSA gadget and test

This commit is contained in:
Nicholas Ward 2021-12-02 10:27:47 -08:00
parent f55948a621
commit b796c73e49
3 changed files with 97 additions and 32 deletions

View File

@ -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<C: Curve> {
pub s: C::ScalarField,
}
pub struct ECDSASecretKey<C: Curve>(C::ScalarField);
pub struct ECDSAPublicKey<C: Curve>(AffinePoint<C>);
pub struct ECDSASecretKey<C: Curve>(pub C::ScalarField);
pub struct ECDSAPublicKey<C: Curve>(pub AffinePoint<C>);
pub fn base_to_scalar<C: Curve>(x: C::BaseField) -> C::ScalarField {
C::ScalarField::from_biguint(x.to_biguint())
@ -22,15 +20,6 @@ pub fn scalar_to_base<C: Curve>(x: C::ScalarField) -> C::BaseField {
C::BaseField::from_biguint(x.to_biguint())
}
pub fn hash_to_scalar<F: RichField, C: Curve>(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<F: RichField>(x: F, num_bits: usize) -> Vec<bool> {
let hashed = hash_n_to_1(vec![x], true);
@ -44,6 +33,15 @@ pub fn hash_to_bits<F: RichField>(x: F, num_bits: usize) -> Vec<bool> {
.collect()
}
pub fn hash_to_scalar<F: RichField, C: Curve>(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<F: RichField, C: Curve>(msg: F, sk: ECDSASecretKey<C>) -> ECDSASignature<C> {
let h = hash_to_scalar::<F, C>(msg, 32);
@ -76,16 +74,14 @@ pub fn verify_message<F: RichField, C: Curve>(
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() {

View File

@ -15,7 +15,7 @@ use crate::plonk::circuit_builder::CircuitBuilder;
#[derive(Clone, Debug)]
pub struct NonNativeTarget<FF: Field> {
pub(crate) value: BigUintTarget,
_phantom: PhantomData<FF>,
pub(crate) _phantom: PhantomData<FF>,
}
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {

View File

@ -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<C: Curve>(NonNativeTarget<C::ScalarField>);
pub struct ECDSAPublicKeyTarget<C: Curve>(AffinePointTarget<C>);
@ -6,48 +18,105 @@ pub struct ECDSASignatureTarget<C: Curve> {
pub s: NonNativeTarget<C::ScalarField>,
}
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
pub fn hash_to_bits(&mut self, x: Target, num_bits: usize) -> Vec<BoolTarget> {
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<C: Curve>(&mut self, x: Target, num_bits: usize) -> NonNativeTarget<C::ScalarField> {
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<C: Curve>(&mut self, msg: Target, sig: ECDSASignatureTarget<C>, pk: ECDSAPublicKeyTarget<C>) {
let ECDSASignatureTarget { r, s } = sig;
let h = self.hash_to_scalar::<C>(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::<C::ScalarField> {
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::<F, D>::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::<C>(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)
}*/
}
}