mirror of
https://github.com/arnaucube/schnorr.git
synced 2026-01-12 17:01:29 +01:00
Prove Schnorr sigs, before deleting power code
This commit is contained in:
2
src/lib.rs
Normal file
2
src/lib.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
mod schnorr;
|
||||||
|
mod schnorr_prover;
|
||||||
149
src/main.rs
149
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<GoldilocksField>) -> u64 {
|
|
||||||
let poseidon_input: Vec<GoldilocksField> = 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<u64>) -> Vec<GoldilocksField> {
|
|
||||||
msg.into_iter()
|
|
||||||
.map(|x| GoldilocksField::from_noncanonical_u64(x))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sign(&self, msg: &Vec<GoldilocksField>, 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<GoldilocksField>, 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() {
|
fn main() {
|
||||||
println!("Hello, world!");
|
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<u64> = vec![17, 123985, 3, 12];
|
|
||||||
let msg0: Vec<GoldilocksField> = 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
140
src/schnorr.rs
Normal file
140
src/schnorr.rs
Normal file
@@ -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<GoldilocksField>) -> u64 {
|
||||||
|
let poseidon_input: Vec<GoldilocksField> = 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<u64>) -> Vec<GoldilocksField> {
|
||||||
|
msg.into_iter()
|
||||||
|
.map(|x| GoldilocksField::from_noncanonical_u64(x))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sign(&self, msg: &Vec<GoldilocksField>, 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<GoldilocksField>, 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<u64> = vec![17, 123985, 3, 12];
|
||||||
|
let msg0: Vec<GoldilocksField> = 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
79
src/schnorr_prover.rs
Normal file
79
src/schnorr_prover.rs
Normal file
@@ -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<D>,
|
||||||
|
C: GenericConfig<D, F = F>,
|
||||||
|
const D: usize
|
||||||
|
> (builder: &mut CircuitBuilder::<F, D>, x: Target, a: Target, num_bits: usize) -> Target {
|
||||||
|
let bits: Vec<BoolTarget> = 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::<GoldilocksField, 2>,
|
||||||
|
sig: &SchnorrSignatureTarget,
|
||||||
|
msg: &Vec<Target>,
|
||||||
|
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<Target> = std::iter::once(r)
|
||||||
|
.chain(msg.iter().cloned())
|
||||||
|
.collect();
|
||||||
|
let e: Target = builder.hash_n_to_hash_no_pad::<PoseidonHash>(
|
||||||
|
hash_input,
|
||||||
|
).elements[0];
|
||||||
|
|
||||||
|
// verify equality
|
||||||
|
builder.connect(e, sig.e);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user