From 22adc43262b36f38be28edd326e19b7902229127 Mon Sep 17 00:00:00 2001 From: Brian Lawrence Date: Sat, 28 Sep 2024 15:42:33 -0700 Subject: [PATCH] Prove Schnorr sigs, before deleting power code --- src/lib.rs | 2 + src/main.rs | 149 ------------------------------------------ src/schnorr.rs | 140 +++++++++++++++++++++++++++++++++++++++ src/schnorr_prover.rs | 79 ++++++++++++++++++++++ 4 files changed, 221 insertions(+), 149 deletions(-) create mode 100644 src/lib.rs create mode 100644 src/schnorr.rs create mode 100644 src/schnorr_prover.rs diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..ac5563c --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,2 @@ +mod schnorr; +mod schnorr_prover; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 987b1f9..e7a11a9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,152 +1,3 @@ -use plonky2::hash::poseidon::PoseidonHash; -use plonky2::field::goldilocks_field::GoldilocksField; -use plonky2::field::types::Field; -use plonky2::plonk::config::Hasher; -use plonky2::field::types::PrimeField64; -use rand; -use rand::Rng; - -const BIG_GROUP_GEN: GoldilocksField = GoldilocksField(14293326489335486720); - -#[derive(Copy, Clone, Debug)] -struct SchnorrSigner { - PRIME_GROUP_GEN: GoldilocksField, - PRIME_GROUP_ORDER: u64, -} - -#[derive(Copy, Clone, Debug)] - -struct SchnorrSecretKey { - sk: u64, -} - -#[derive(Copy, Clone, Debug)] -struct SchnorrPublicKey { - pk: GoldilocksField, -} - -#[derive(Copy, Clone, Debug)] -struct SchnorrSignature { - s: u64, - e: u64, -} - -impl SchnorrSigner{ - fn new() -> Self { - let quotient_order: u64 = (1 << 48) - (1 << 32); - let PRIME_GROUP_GEN: GoldilocksField = Self::pow(BIG_GROUP_GEN, quotient_order); - let PRIME_GROUP_ORDER: u64 = (1 << 16) + 1; - SchnorrSigner{PRIME_GROUP_GEN, PRIME_GROUP_ORDER} - } - - fn pow(x: GoldilocksField, a: u64) -> GoldilocksField { - let mut a_copy = a; - let mut res = GoldilocksField(1); - let mut x_pow_2n = x.clone(); - while (a_copy > 0) { - if (a_copy % 2 != 0) { - res *= x_pow_2n; - } - a_copy /= 2; - x_pow_2n *= x_pow_2n; - } - res - } - - fn keygen(&self, sk: &SchnorrSecretKey) -> SchnorrPublicKey { - let pk: GoldilocksField = Self::pow(self.PRIME_GROUP_GEN, sk.sk).inverse(); - println!("{:?}", self.PRIME_GROUP_GEN); - // self.PRIME_GROUP_GEN is 6612579038192137166 - SchnorrPublicKey{pk: pk} - } - - fn hash_insecure(&self, r: &GoldilocksField, msg: &Vec) -> u64 { - let poseidon_input: Vec = std::iter::once(r) - .chain(msg.iter()) - .copied() - .collect(); - - println!("Running hash on concatenated elts: {:?}", poseidon_input); - let h = PoseidonHash::hash_no_pad(&poseidon_input); - h.elements[0].to_canonical_u64() % self.PRIME_GROUP_ORDER - } - - fn rand_group_multiplier(&self, rng: &mut rand::rngs::ThreadRng) -> u64 { - let group_order: u64 = (1 << 16) + 1; - rng.gen_range(0..group_order) - } - - fn u64_into_goldilocks_vec(&self, msg: Vec) -> Vec { - msg.into_iter() - .map(|x| GoldilocksField::from_noncanonical_u64(x)) - .collect() - } - - fn sign(&self, msg: &Vec, sk: &SchnorrSecretKey, rng: &mut rand::rngs::ThreadRng) -> SchnorrSignature { - let k: u64 = self.rand_group_multiplier(rng); - let r: GoldilocksField = Self::pow(self.PRIME_GROUP_GEN, k); - let e: u64 = self.hash_insecure(&r, msg); - assert!(k < self.PRIME_GROUP_ORDER); - assert!(sk.sk < self.PRIME_GROUP_ORDER); - assert!(e < self.PRIME_GROUP_ORDER); - //println!("Super secret k: {:?}", k); - //println!("Super secret r: {:?}", r); - //println!("PRIME_GROUP_ORDER: {:?}", self.PRIME_GROUP_ORDER); - let mut s128: u128 = ((k as u128) + (sk.sk as u128) * (e as u128)); - s128 %= self.PRIME_GROUP_ORDER as u128; - let s: u64 = s128 as u64; - SchnorrSignature{e, s} - } - - fn verify(&self, sig: &SchnorrSignature, msg: &Vec, pk: &SchnorrPublicKey) -> bool { - let r: GoldilocksField = Self::pow(self.PRIME_GROUP_GEN, sig.s) - * Self::pow(pk.pk, sig.e); - let e_v: u64 = self.hash_insecure(&r, msg); - e_v == sig.e - } -} - fn main() { println!("Hello, world!"); - - let mut rng: rand::rngs::ThreadRng = rand::thread_rng(); - - type F = GoldilocksField; - - let x = F::from_noncanonical_i64(3); - let h = PoseidonHash::hash_no_pad(&[x]); - println!("Hash is {:?}", h); } - -#[cfg(test)] -mod tests { - use plonky2::field::goldilocks_field::GoldilocksField; - - use crate::{SchnorrPublicKey, SchnorrSecretKey, SchnorrSigner, SchnorrSignature}; - - #[test] - fn test_pow() { - let g = GoldilocksField(3); - let res = GoldilocksField(16305451354880172407); - assert_eq!(res, SchnorrSigner::pow(g, 1234567)); - } - - #[test] - fn test_sig() { - println!("NOT IMPLEMENTED"); - let mut rng: rand::rngs::ThreadRng = rand::thread_rng(); - let ss = SchnorrSigner::new(); - let sk: SchnorrSecretKey = SchnorrSecretKey{ sk: 1422 }; - let pk: SchnorrPublicKey = ss.keygen(&sk); - - let msg0_u64: Vec = vec![17, 123985, 3, 12]; - let msg0: Vec = ss.u64_into_goldilocks_vec(msg0_u64); - let sig: SchnorrSignature = ss.sign(&msg0, &sk, &mut rng); - let res: bool = ss.verify(&sig, &msg0, &pk); - println!("Trying to verify:"); - println!("Secret key: {:?}", sk); - println!("Public key: {:?}", pk); - println!("Signature: {:?}", sig); - assert!(res); - } -} \ No newline at end of file diff --git a/src/schnorr.rs b/src/schnorr.rs new file mode 100644 index 0000000..85b5394 --- /dev/null +++ b/src/schnorr.rs @@ -0,0 +1,140 @@ +use plonky2::hash::poseidon::PoseidonHash; +use plonky2::field::goldilocks_field::GoldilocksField; +use plonky2::field::types::Field; +use plonky2::plonk::config::Hasher; +use plonky2::field::types::PrimeField64; +use rand; +use rand::Rng; + +const BIG_GROUP_GEN: GoldilocksField = GoldilocksField(14293326489335486720); + +#[derive(Copy, Clone, Debug)] +struct SchnorrSigner { + PRIME_GROUP_GEN: GoldilocksField, + PRIME_GROUP_ORDER: u64, +} + +#[derive(Copy, Clone, Debug)] + +struct SchnorrSecretKey { + sk: u64, +} + +#[derive(Copy, Clone, Debug)] +struct SchnorrPublicKey { + pk: GoldilocksField, +} + +#[derive(Copy, Clone, Debug)] +struct SchnorrSignature { + s: u64, + e: u64, +} + +impl SchnorrSigner{ + fn new() -> Self { + let quotient_order: u64 = (1 << 48) - (1 << 32); + let PRIME_GROUP_GEN: GoldilocksField = Self::pow(BIG_GROUP_GEN, quotient_order); + let PRIME_GROUP_ORDER: u64 = (1 << 16) + 1; + SchnorrSigner{PRIME_GROUP_GEN, PRIME_GROUP_ORDER} + } + + fn pow(x: GoldilocksField, a: u64) -> GoldilocksField { + let mut a_copy = a; + let mut res = GoldilocksField(1); + let mut x_pow_2n = x.clone(); + while (a_copy > 0) { + if (a_copy % 2 != 0) { + res *= x_pow_2n; + } + a_copy /= 2; + x_pow_2n *= x_pow_2n; + } + res + } + + fn keygen(&self, sk: &SchnorrSecretKey) -> SchnorrPublicKey { + let pk: GoldilocksField = Self::pow(self.PRIME_GROUP_GEN, sk.sk).inverse(); + println!("{:?}", self.PRIME_GROUP_GEN); + // self.PRIME_GROUP_GEN is 6612579038192137166 + SchnorrPublicKey{pk: pk} + } + + fn hash_insecure(&self, r: &GoldilocksField, msg: &Vec) -> u64 { + let poseidon_input: Vec = std::iter::once(r) + .chain(msg.iter()) + .copied() + .collect(); + + println!("Running hash on concatenated elts: {:?}", poseidon_input); + let h = PoseidonHash::hash_no_pad(&poseidon_input); + h.elements[0].to_canonical_u64() % self.PRIME_GROUP_ORDER + } + + fn rand_group_multiplier(&self, rng: &mut rand::rngs::ThreadRng) -> u64 { + let group_order: u64 = (1 << 16) + 1; + rng.gen_range(0..group_order) + } + + fn u64_into_goldilocks_vec(&self, msg: Vec) -> Vec { + msg.into_iter() + .map(|x| GoldilocksField::from_noncanonical_u64(x)) + .collect() + } + + fn sign(&self, msg: &Vec, sk: &SchnorrSecretKey, rng: &mut rand::rngs::ThreadRng) -> SchnorrSignature { + let k: u64 = self.rand_group_multiplier(rng); + let r: GoldilocksField = Self::pow(self.PRIME_GROUP_GEN, k); + let e: u64 = self.hash_insecure(&r, msg); + assert!(k < self.PRIME_GROUP_ORDER); + assert!(sk.sk < self.PRIME_GROUP_ORDER); + assert!(e < self.PRIME_GROUP_ORDER); + //println!("Super secret k: {:?}", k); + //println!("Super secret r: {:?}", r); + //println!("PRIME_GROUP_ORDER: {:?}", self.PRIME_GROUP_ORDER); + let mut s128: u128 = ((k as u128) + (sk.sk as u128) * (e as u128)); + s128 %= self.PRIME_GROUP_ORDER as u128; + let s: u64 = s128 as u64; + SchnorrSignature{e, s} + } + + fn verify(&self, sig: &SchnorrSignature, msg: &Vec, pk: &SchnorrPublicKey) -> bool { + let r: GoldilocksField = Self::pow(self.PRIME_GROUP_GEN, sig.s) + * Self::pow(pk.pk, sig.e); + let e_v: u64 = self.hash_insecure(&r, msg); + e_v == sig.e + } +} + +#[cfg(test)] +mod tests { + use plonky2::field::goldilocks_field::GoldilocksField; + + use crate::schnorr::{SchnorrPublicKey, SchnorrSecretKey, SchnorrSigner, SchnorrSignature}; + + #[test] + fn test_pow() { + let g = GoldilocksField(3); + let res = GoldilocksField(16305451354880172407); + assert_eq!(res, SchnorrSigner::pow(g, 1234567)); + } + + #[test] + fn test_sig() { + println!("NOT IMPLEMENTED"); + let mut rng: rand::rngs::ThreadRng = rand::thread_rng(); + let ss = SchnorrSigner::new(); + let sk: SchnorrSecretKey = SchnorrSecretKey{ sk: 1422 }; + let pk: SchnorrPublicKey = ss.keygen(&sk); + + let msg0_u64: Vec = vec![17, 123985, 3, 12]; + let msg0: Vec = ss.u64_into_goldilocks_vec(msg0_u64); + let sig: SchnorrSignature = ss.sign(&msg0, &sk, &mut rng); + let res: bool = ss.verify(&sig, &msg0, &pk); + println!("Trying to verify:"); + println!("Secret key: {:?}", sk); + println!("Public key: {:?}", pk); + println!("Signature: {:?}", sig); + assert!(res); + } +} \ No newline at end of file diff --git a/src/schnorr_prover.rs b/src/schnorr_prover.rs new file mode 100644 index 0000000..cd85c1b --- /dev/null +++ b/src/schnorr_prover.rs @@ -0,0 +1,79 @@ +use anyhow::Result; +use plonky2::field::extension::{Extendable, FieldExtension}; +use plonky2::field::types::Field; +use plonky2::field::goldilocks_field::GoldilocksField; +use plonky2::hash::hash_types::RichField; +use plonky2::hash::poseidon::PoseidonHash; +use plonky2::iop::target::{BoolTarget, Target}; +use plonky2::iop::witness::{PartialWitness, WitnessWrite}; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, CommonCircuitData, VerifierCircuitData, VerifierOnlyCircuitData}; +use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; +use plonky2::plonk::proof::ProofWithPublicInputs; + +pub struct SchnorrSignatureTarget { + s: Target, + e: Target, +} + +pub struct SchnorrPublicKeyTarget { + pk: Target, +} + +pub struct SchnorrBuilder { + +} + +impl SchnorrBuilder { + // the output Target is constrained to equal x^a + // here we assume that + + // waaait, maybe I can use their built in thing + fn prove_power< + F: RichField + Extendable, + C: GenericConfig, + const D: usize + > (builder: &mut CircuitBuilder::, x: Target, a: Target, num_bits: usize) -> Target { + let bits: Vec = builder.split_le(a, num_bits); + // make a sequence of targets x_i + // where x_0 = 1 + // x_{num_bits} = x^a + // and in between: + // x_i = x_{i-1}**2 * (bits[num_bits+1-i] ? 1 : x) + + } + + fn constrain_sig < + C: GenericConfig<2, F = GoldilocksField>, + > ( + builder: &mut CircuitBuilder::, + sig: &SchnorrSignatureTarget, + msg: &Vec, + pk: &SchnorrPublicKeyTarget, + ) -> () { + let PRIME_GROUP_GEN: Target = builder.constant(GoldilocksField::from_canonical_u64(6612579038192137166)); + const num_bits_exp: usize = 32; + + /* + let r: GoldilocksField = Self::pow(self.PRIME_GROUP_GEN, sig.s) + * Self::pow(pk.pk, sig.e); + let e_v: u64 = self.hash_insecure(&r, msg); + e_v == sig.e */ + + let gs: Target = builder.exp(PRIME_GROUP_GEN, sig.s, num_bits_exp); + let pe: Target = builder.exp(pk.pk, sig.e, num_bits_exp); + let r: Target = builder.mul(gs, pe); + + // compute hash + let hash_input: Vec = std::iter::once(r) + .chain(msg.iter().cloned()) + .collect(); + let e: Target = builder.hash_n_to_hash_no_pad::( + hash_input, + ).elements[0]; + + // verify equality + builder.connect(e, sig.e); + + } +} \ No newline at end of file