mirror of
https://github.com/arnaucube/schnorr.git
synced 2026-01-12 17:01:29 +01:00
Schnorr proofs in progress
This commit is contained in:
@@ -9,30 +9,30 @@ use rand::Rng;
|
|||||||
const BIG_GROUP_GEN: GoldilocksField = GoldilocksField(14293326489335486720);
|
const BIG_GROUP_GEN: GoldilocksField = GoldilocksField(14293326489335486720);
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
struct SchnorrSigner {
|
pub struct SchnorrSigner {
|
||||||
PRIME_GROUP_GEN: GoldilocksField,
|
PRIME_GROUP_GEN: GoldilocksField,
|
||||||
PRIME_GROUP_ORDER: u64,
|
PRIME_GROUP_ORDER: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
|
||||||
struct SchnorrSecretKey {
|
pub struct SchnorrSecretKey {
|
||||||
sk: u64,
|
pub sk: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
struct SchnorrPublicKey {
|
pub struct SchnorrPublicKey {
|
||||||
pk: GoldilocksField,
|
pub pk: GoldilocksField,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
struct SchnorrSignature {
|
pub struct SchnorrSignature {
|
||||||
s: u64,
|
pub s: u64,
|
||||||
e: u64,
|
pub e: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SchnorrSigner{
|
impl SchnorrSigner{
|
||||||
fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let quotient_order: u64 = (1 << 48) - (1 << 32);
|
let quotient_order: u64 = (1 << 48) - (1 << 32);
|
||||||
let PRIME_GROUP_GEN: GoldilocksField = Self::pow(BIG_GROUP_GEN, quotient_order);
|
let PRIME_GROUP_GEN: GoldilocksField = Self::pow(BIG_GROUP_GEN, quotient_order);
|
||||||
let PRIME_GROUP_ORDER: u64 = (1 << 16) + 1;
|
let PRIME_GROUP_ORDER: u64 = (1 << 16) + 1;
|
||||||
@@ -53,7 +53,7 @@ impl SchnorrSigner{
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
fn keygen(&self, sk: &SchnorrSecretKey) -> SchnorrPublicKey {
|
pub fn keygen(&self, sk: &SchnorrSecretKey) -> SchnorrPublicKey {
|
||||||
let pk: GoldilocksField = Self::pow(self.PRIME_GROUP_GEN, sk.sk).inverse();
|
let pk: GoldilocksField = Self::pow(self.PRIME_GROUP_GEN, sk.sk).inverse();
|
||||||
println!("{:?}", self.PRIME_GROUP_GEN);
|
println!("{:?}", self.PRIME_GROUP_GEN);
|
||||||
// self.PRIME_GROUP_GEN is 6612579038192137166
|
// self.PRIME_GROUP_GEN is 6612579038192137166
|
||||||
@@ -76,13 +76,13 @@ impl SchnorrSigner{
|
|||||||
rng.gen_range(0..group_order)
|
rng.gen_range(0..group_order)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn u64_into_goldilocks_vec(&self, msg: Vec<u64>) -> Vec<GoldilocksField> {
|
pub fn u64_into_goldilocks_vec(&self, msg: Vec<u64>) -> Vec<GoldilocksField> {
|
||||||
msg.into_iter()
|
msg.into_iter()
|
||||||
.map(|x| GoldilocksField::from_noncanonical_u64(x))
|
.map(|x| GoldilocksField::from_noncanonical_u64(x))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign(&self, msg: &Vec<GoldilocksField>, sk: &SchnorrSecretKey, rng: &mut rand::rngs::ThreadRng) -> SchnorrSignature {
|
pub fn sign(&self, msg: &Vec<GoldilocksField>, sk: &SchnorrSecretKey, rng: &mut rand::rngs::ThreadRng) -> SchnorrSignature {
|
||||||
let k: u64 = self.rand_group_multiplier(rng);
|
let k: u64 = self.rand_group_multiplier(rng);
|
||||||
let r: GoldilocksField = Self::pow(self.PRIME_GROUP_GEN, k);
|
let r: GoldilocksField = Self::pow(self.PRIME_GROUP_GEN, k);
|
||||||
let e: u64 = self.hash_insecure(&r, msg);
|
let e: u64 = self.hash_insecure(&r, msg);
|
||||||
@@ -98,7 +98,7 @@ impl SchnorrSigner{
|
|||||||
SchnorrSignature{e, s}
|
SchnorrSignature{e, s}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify(&self, sig: &SchnorrSignature, msg: &Vec<GoldilocksField>, pk: &SchnorrPublicKey) -> bool {
|
pub fn verify(&self, sig: &SchnorrSignature, msg: &Vec<GoldilocksField>, pk: &SchnorrPublicKey) -> bool {
|
||||||
let r: GoldilocksField = Self::pow(self.PRIME_GROUP_GEN, sig.s)
|
let r: GoldilocksField = Self::pow(self.PRIME_GROUP_GEN, sig.s)
|
||||||
* Self::pow(pk.pk, sig.e);
|
* Self::pow(pk.pk, sig.e);
|
||||||
let e_v: u64 = self.hash_insecure(&r, msg);
|
let e_v: u64 = self.hash_insecure(&r, msg);
|
||||||
|
|||||||
@@ -11,47 +11,105 @@ use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, CommonCircuitData
|
|||||||
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||||
use plonky2::plonk::proof::ProofWithPublicInputs;
|
use plonky2::plonk::proof::ProofWithPublicInputs;
|
||||||
|
|
||||||
|
pub struct MessageTarget {
|
||||||
|
msg: Vec<Target>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MessageTarget {
|
||||||
|
fn new_with_size(builder: &mut CircuitBuilder<GoldilocksField, 2>, n: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
msg: builder.add_virtual_targets(n),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct SchnorrSignatureTarget {
|
pub struct SchnorrSignatureTarget {
|
||||||
s: Target,
|
s: Target,
|
||||||
e: Target,
|
e: Target,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SchnorrSignatureTarget {
|
||||||
|
fn new_virtual(builder: &mut CircuitBuilder<GoldilocksField, 2>) -> Self {
|
||||||
|
let s = builder.add_virtual_target();
|
||||||
|
let e = builder.add_virtual_target();
|
||||||
|
Self{ s, e }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct SchnorrPublicKeyTarget {
|
pub struct SchnorrPublicKeyTarget {
|
||||||
pk: Target,
|
pk: Target,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Mod65537Generator {
|
||||||
|
a: Target,
|
||||||
|
q: Target,
|
||||||
|
r: Target,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct SchnorrBuilder {
|
pub struct SchnorrBuilder {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SchnorrBuilder {
|
impl SchnorrBuilder {
|
||||||
// the output Target is constrained to equal x^a
|
// Reduce a modulo the constant 65537
|
||||||
// here we assume that
|
// where a is the canonical representative for an element of the field
|
||||||
|
// (meaning: 0 \leq a < p)
|
||||||
|
|
||||||
// waaait, maybe I can use their built in thing
|
// To verify this, write
|
||||||
fn prove_power<
|
// a = 65537 * q + r, and do range checks to check that:
|
||||||
F: RichField + Extendable<D>,
|
// 0 <= q <= floor(p / 65537)
|
||||||
C: GenericConfig<D, F = F>,
|
// 0 <= r < 65537
|
||||||
const D: usize
|
// (these first two checks guarantee that a lies in the range [0, p + 65536])
|
||||||
> (builder: &mut CircuitBuilder::<F, D>, x: Target, a: Target, num_bits: usize) -> Target {
|
// if q = floor(p / 65537) then r = 0
|
||||||
let bits: Vec<BoolTarget> = builder.split_le(a, num_bits);
|
// (note that p % 65537 == 1 so this is the only possibility)
|
||||||
// make a sequence of targets x_i
|
fn mod_65537 <
|
||||||
// where x_0 = 1
|
C: GenericConfig<2, F = GoldilocksField>,
|
||||||
// x_{num_bits} = x^a
|
> (
|
||||||
// and in between:
|
builder: &mut CircuitBuilder::<GoldilocksField, 2>,
|
||||||
// x_i = x_{i-1}**2 * (bits[num_bits+1-i] ? 1 : x)
|
a: &Target,
|
||||||
|
) -> Target {
|
||||||
|
let q = builder.add_virtual_target();
|
||||||
|
let r = builder.add_virtual_target();
|
||||||
|
|
||||||
|
// the Mod65537Generator will assign values to q and r later
|
||||||
|
builder.add_simple_generator( Mod65537Generator { a, q, r } );
|
||||||
|
|
||||||
|
// impose four constraints
|
||||||
|
// 1. a = 65537 * q + r
|
||||||
|
let t65537 = builder.constant(GoldilocksField::from_canonical_u64(65537));
|
||||||
|
let a_copy = builder.mul_add(t65537, q, r);
|
||||||
|
builder.connect(*a, a_copy);
|
||||||
|
|
||||||
|
// 2. 0 <= q <= floor(p / 65537)
|
||||||
|
// max_q is 281470681743360 = floor(p / 65537) = (p-1) / 65537 = 2^48 - 2^32
|
||||||
|
let max_q = builder.constant(GoldilocksField::from_canonical_u64(281470681743360));
|
||||||
|
builder.range_check(q, 48);
|
||||||
|
builder.range_check(builder.sub(max_q, q), 48);
|
||||||
|
|
||||||
|
// 3. 0 <= r < 65537
|
||||||
|
let max_r = builder.constant(GoldilocksField::from_canonical_u64(65537));
|
||||||
|
builder.range_check(r, 17);
|
||||||
|
builder.range_check(builder.sub(max_r, r), 17);
|
||||||
|
|
||||||
|
// 4. if q = floor(p / 65537) then r = 0
|
||||||
|
let q_equals_max = builder.is_equal(q, max_q);
|
||||||
|
builder.connect(builder.mul(q_equals_max.target, r), builder.zero());
|
||||||
|
|
||||||
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
fn constrain_sig <
|
fn constrain_sig <
|
||||||
C: GenericConfig<2, F = GoldilocksField>,
|
C: GenericConfig<2, F = GoldilocksField>,
|
||||||
> (
|
> (
|
||||||
|
&self,
|
||||||
builder: &mut CircuitBuilder::<GoldilocksField, 2>,
|
builder: &mut CircuitBuilder::<GoldilocksField, 2>,
|
||||||
sig: &SchnorrSignatureTarget,
|
sig: &SchnorrSignatureTarget,
|
||||||
msg: &Vec<Target>,
|
msg: &MessageTarget,
|
||||||
pk: &SchnorrPublicKeyTarget,
|
pk: &SchnorrPublicKeyTarget,
|
||||||
) -> () {
|
) -> () {
|
||||||
let PRIME_GROUP_GEN: Target = builder.constant(GoldilocksField::from_canonical_u64(6612579038192137166));
|
let PRIME_GROUP_GEN: Target = builder.constant(GoldilocksField::from_canonical_u64(6612579038192137166));
|
||||||
|
let PRIME_GROUP_ORDER: Target = builder.constant(GoldilocksField::from_canonical_u64(65537));
|
||||||
const num_bits_exp: usize = 32;
|
const num_bits_exp: usize = 32;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -65,15 +123,61 @@ impl SchnorrBuilder {
|
|||||||
let r: Target = builder.mul(gs, pe);
|
let r: Target = builder.mul(gs, pe);
|
||||||
|
|
||||||
// compute hash
|
// compute hash
|
||||||
|
// note that it's safe to clone Targets since they just contain indices
|
||||||
let hash_input: Vec<Target> = std::iter::once(r)
|
let hash_input: Vec<Target> = std::iter::once(r)
|
||||||
.chain(msg.iter().cloned())
|
.chain(msg.iter().cloned())
|
||||||
.collect();
|
.collect();
|
||||||
let e: Target = builder.hash_n_to_hash_no_pad::<PoseidonHash>(
|
let e: Target = builder.hash_n_to_hash_no_pad::<PoseidonHash>(
|
||||||
hash_input,
|
hash_input,
|
||||||
).elements[0];
|
).elements[0] // whoops have to take mod group order;
|
||||||
|
|
||||||
// verify equality
|
// enforce equality
|
||||||
builder.connect(e, sig.e);
|
builder.connect(e, sig.e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests{
|
||||||
|
use crate::schnorr::{SchnorrPublicKey, SchnorrSecretKey, SchnorrSigner, SchnorrSignature};
|
||||||
|
use crate::schnorr_prover::SchnorrBuilder;
|
||||||
|
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||||
|
use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, CommonCircuitData, VerifierCircuitData, VerifierOnlyCircuitData};
|
||||||
|
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||||
|
use plonky2::field::goldilocks_field::GoldilocksField;
|
||||||
|
use rand;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_schnorr() -> () {
|
||||||
|
const D: usize = 2;
|
||||||
|
type C = PoseidonGoldilocksConfig;
|
||||||
|
type F = <C as GenericConfig<D>>::F;
|
||||||
|
|
||||||
|
let mut rng: rand::rngs::ThreadRng = rand::thread_rng();
|
||||||
|
|
||||||
|
let config = CircuitConfig::standard_recursion_config();
|
||||||
|
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||||
|
|
||||||
|
builder.add_virtual_fri_proof(num_leaves_per_oracle, params)
|
||||||
|
|
||||||
|
let sb: SchnorrBuilder = SchnorrBuilder{};
|
||||||
|
|
||||||
|
// create keypair, message, signature
|
||||||
|
let sk: SchnorrSecretKey = SchnorrSecretKey{ sk: 133 };
|
||||||
|
let ss = SchnorrSigner::new();
|
||||||
|
let pk: SchnorrPublicKey = ss.keygen(&sk);
|
||||||
|
let msg: Vec<GoldilocksField> = ss.u64_into_goldilocks_vec(
|
||||||
|
vec![1500, 1600, 0, 0, 0]
|
||||||
|
);
|
||||||
|
let msg_size: usize = msg.len();
|
||||||
|
let sig: SchnorrSignature = ss.sign(&msg, &sk, &mut rng);
|
||||||
|
|
||||||
|
let sig_target = builder.constant(sig);
|
||||||
|
// instead of verifying we're going to prove the verification
|
||||||
|
sb.constrain_sig(
|
||||||
|
&mut builder,
|
||||||
|
&sig,
|
||||||
|
&msg,
|
||||||
|
&pk
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user