mirror of
https://github.com/arnaucube/protogalaxy-poc.git
synced 2026-01-12 00:41:35 +01:00
port pedersen.rs & transcript.rs from https://github.com/arnaucube/nova-study
This commit is contained in:
11
Cargo.toml
11
Cargo.toml
@@ -6,3 +6,14 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
ark-std = "0.4.0"
|
||||
ark-ff = "0.4.0"
|
||||
ark-ec = { version = "0.4.0", default-features = false }
|
||||
ark-poly = "0.4.0"
|
||||
ark-serialize = { version = "0.4.0", default-features = false, features = [ "derive" ] }
|
||||
rand = { version = "0.8", features = [ "std", "std_rng" ] }
|
||||
merlin = { version = "3.0.0" }
|
||||
ark-crypto-primitives = { version = "^0.4.0", default-features = false, features = [ "r1cs", "snark", "sponge", "crh" ] }
|
||||
|
||||
[dev-dependencies]
|
||||
ark-bls12-381 = "0.4.0"
|
||||
|
||||
20
src/lib.rs
20
src/lib.rs
@@ -1,14 +1,8 @@
|
||||
pub fn add(left: usize, right: usize) -> usize {
|
||||
left + right
|
||||
}
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(unused)] // TMP
|
||||
#![allow(dead_code)] // TMP
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let result = add(2, 2);
|
||||
assert_eq!(result, 4);
|
||||
}
|
||||
}
|
||||
pub mod pedersen;
|
||||
pub mod transcript;
|
||||
pub mod utils;
|
||||
|
||||
232
src/pedersen.rs
Normal file
232
src/pedersen.rs
Normal file
@@ -0,0 +1,232 @@
|
||||
/// pedersen.rs file and adapted from https://github.com/arnaucube/nova-study
|
||||
use ark_ec::{CurveGroup, Group};
|
||||
use ark_std::{
|
||||
rand::{Rng, RngCore},
|
||||
UniformRand,
|
||||
};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use crate::utils::{vec_add, vec_scalar_mul};
|
||||
|
||||
use crate::transcript::Transcript;
|
||||
use ark_crypto_primitives::sponge::Absorb;
|
||||
|
||||
pub struct ProofElem<C: CurveGroup> {
|
||||
R: C,
|
||||
t1: C::ScalarField,
|
||||
t2: C::ScalarField,
|
||||
}
|
||||
pub struct Proof<C: CurveGroup> {
|
||||
R: C,
|
||||
u_: Vec<C::ScalarField>,
|
||||
ru_: C::ScalarField,
|
||||
}
|
||||
|
||||
pub struct Params<C: CurveGroup> {
|
||||
g: C,
|
||||
h: C,
|
||||
pub generators: Vec<C::Affine>,
|
||||
}
|
||||
|
||||
pub struct Pedersen<C: CurveGroup>
|
||||
where
|
||||
<C as Group>::ScalarField: Absorb,
|
||||
<C as CurveGroup>::BaseField: Absorb,
|
||||
{
|
||||
_c: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<C: CurveGroup> Pedersen<C>
|
||||
where
|
||||
<C as Group>::ScalarField: Absorb,
|
||||
<C as CurveGroup>::BaseField: Absorb,
|
||||
{
|
||||
pub fn new_params<R: Rng>(rng: &mut R, max: usize) -> Params<C> {
|
||||
let h_scalar = C::ScalarField::rand(rng);
|
||||
let g: C = C::generator();
|
||||
let generators: Vec<C::Affine> = vec![C::Affine::rand(rng); max];
|
||||
let params: Params<C> = Params::<C> {
|
||||
g,
|
||||
h: g.mul(h_scalar),
|
||||
generators,
|
||||
};
|
||||
params
|
||||
}
|
||||
|
||||
pub fn commit_elem<R: RngCore>(
|
||||
rng: &mut R,
|
||||
params: &Params<C>,
|
||||
v: &C::ScalarField,
|
||||
) -> CommitmentElem<C> {
|
||||
let r = C::ScalarField::rand(rng);
|
||||
let cm: C = params.g.mul(v) + params.h.mul(r);
|
||||
CommitmentElem::<C> { cm, r }
|
||||
}
|
||||
pub fn commit(
|
||||
params: &Params<C>,
|
||||
v: &Vec<C::ScalarField>,
|
||||
r: &C::ScalarField, // random value is provided, in order to be choosen by other parts of the protocol
|
||||
) -> Commitment<C> {
|
||||
let cm = params.h.mul(r) + C::msm(¶ms.generators, v).unwrap();
|
||||
Commitment::<C>(cm)
|
||||
}
|
||||
|
||||
pub fn prove_elem(
|
||||
params: &Params<C>,
|
||||
transcript: &mut Transcript<C::ScalarField, C>,
|
||||
cm: C,
|
||||
v: C::ScalarField,
|
||||
r: C::ScalarField,
|
||||
) -> ProofElem<C> {
|
||||
let r1 = transcript.get_challenge();
|
||||
let r2 = transcript.get_challenge();
|
||||
|
||||
let R: C = params.g.mul(r1) + params.h.mul(r2);
|
||||
|
||||
transcript.add_point(&cm);
|
||||
transcript.add_point(&R);
|
||||
let e = transcript.get_challenge();
|
||||
|
||||
let t1 = r1 + v * e;
|
||||
let t2 = r2 + r * e;
|
||||
|
||||
ProofElem::<C> { R, t1, t2 }
|
||||
}
|
||||
pub fn prove(
|
||||
params: &Params<C>,
|
||||
transcript: &mut Transcript<C::ScalarField, C>,
|
||||
cm: &Commitment<C>, // TODO maybe it makes sense to not have a type wrapper and use directly C
|
||||
v: &Vec<C::ScalarField>,
|
||||
r: &C::ScalarField,
|
||||
) -> Proof<C> {
|
||||
let r1 = transcript.get_challenge();
|
||||
let d = transcript.get_challenge_vec(v.len());
|
||||
|
||||
let R: C = params.h.mul(r1) + C::msm(¶ms.generators, &d).unwrap();
|
||||
|
||||
transcript.add_point(&cm.0);
|
||||
transcript.add_point(&R);
|
||||
let e = transcript.get_challenge();
|
||||
|
||||
let u_ = vec_add(&vec_scalar_mul(v, &e), &d);
|
||||
let ru_ = e * r + r1;
|
||||
|
||||
Proof::<C> { R, u_, ru_ }
|
||||
}
|
||||
pub fn verify(
|
||||
params: &Params<C>,
|
||||
transcript: &mut Transcript<C::ScalarField, C>,
|
||||
cm: Commitment<C>,
|
||||
proof: Proof<C>,
|
||||
) -> bool {
|
||||
// r1, d just to match Prover's transcript
|
||||
transcript.get_challenge(); // r_1
|
||||
transcript.get_challenge_vec(proof.u_.len()); // d
|
||||
|
||||
transcript.add_point(&cm.0);
|
||||
transcript.add_point(&proof.R);
|
||||
let e = transcript.get_challenge();
|
||||
let lhs = proof.R + cm.0.mul(e);
|
||||
let rhs = params.h.mul(proof.ru_) + C::msm(¶ms.generators, &proof.u_).unwrap();
|
||||
if lhs != rhs {
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn verify_elem(
|
||||
params: &Params<C>,
|
||||
transcript: &mut Transcript<C::ScalarField, C>,
|
||||
cm: C,
|
||||
proof: ProofElem<C>,
|
||||
) -> bool {
|
||||
// s1, s2 just to match Prover's transcript
|
||||
transcript.get_challenge(); // r_1
|
||||
transcript.get_challenge(); // r_2
|
||||
|
||||
transcript.add_point(&cm);
|
||||
transcript.add_point(&proof.R);
|
||||
let e = transcript.get_challenge();
|
||||
let lhs = proof.R + cm.mul(e);
|
||||
let rhs = params.g.mul(proof.t1) + params.h.mul(proof.t2);
|
||||
if lhs != rhs {
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Commitment<C: CurveGroup>(pub C);
|
||||
|
||||
pub struct CommitmentElem<C: CurveGroup> {
|
||||
pub cm: C,
|
||||
pub r: C::ScalarField,
|
||||
}
|
||||
impl<C: CurveGroup> CommitmentElem<C>
|
||||
where
|
||||
<C as Group>::ScalarField: Absorb,
|
||||
<C as CurveGroup>::BaseField: Absorb,
|
||||
{
|
||||
pub fn prove(
|
||||
&self,
|
||||
params: &Params<C>,
|
||||
transcript: &mut Transcript<C::ScalarField, C>,
|
||||
v: C::ScalarField,
|
||||
) -> ProofElem<C> {
|
||||
Pedersen::<C>::prove_elem(params, transcript, self.cm, v, self.r)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::transcript::poseidon_test_config;
|
||||
use ark_bls12_381::{Fr, G1Projective};
|
||||
|
||||
#[test]
|
||||
fn test_pedersen_single_element() {
|
||||
let mut rng = ark_std::test_rng();
|
||||
|
||||
// setup params
|
||||
let params = Pedersen::<G1Projective>::new_params(
|
||||
&mut rng, 0, /* 0, as here we don't use commit_vec */
|
||||
);
|
||||
let poseidon_config = poseidon_test_config::<Fr>();
|
||||
|
||||
// init Prover's transcript
|
||||
let mut transcript_p = Transcript::<Fr, G1Projective>::new(&poseidon_config);
|
||||
// init Verifier's transcript
|
||||
let mut transcript_v = Transcript::<Fr, G1Projective>::new(&poseidon_config);
|
||||
|
||||
let v = Fr::rand(&mut rng);
|
||||
|
||||
let cm = Pedersen::commit_elem(&mut rng, ¶ms, &v);
|
||||
let proof = cm.prove(¶ms, &mut transcript_p, v);
|
||||
// also can use:
|
||||
// let proof = Pedersen::prove_elem(¶ms, &mut transcript_p, cm.cm, v, cm.r);
|
||||
let v = Pedersen::verify_elem(¶ms, &mut transcript_v, cm.cm, proof);
|
||||
assert!(v);
|
||||
}
|
||||
#[test]
|
||||
fn test_pedersen_vector() {
|
||||
let mut rng = ark_std::test_rng();
|
||||
|
||||
const n: usize = 10;
|
||||
// setup params
|
||||
let params = Pedersen::<G1Projective>::new_params(&mut rng, n);
|
||||
let poseidon_config = poseidon_test_config::<Fr>();
|
||||
|
||||
// init Prover's transcript
|
||||
let mut transcript_p = Transcript::<Fr, G1Projective>::new(&poseidon_config);
|
||||
// init Verifier's transcript
|
||||
let mut transcript_v = Transcript::<Fr, G1Projective>::new(&poseidon_config);
|
||||
|
||||
let v: Vec<Fr> = vec![Fr::rand(&mut rng); n];
|
||||
let r: Fr = Fr::rand(&mut rng);
|
||||
let cm = Pedersen::commit(¶ms, &v, &r);
|
||||
let proof = Pedersen::prove(¶ms, &mut transcript_p, &cm, &v, &r);
|
||||
let v = Pedersen::verify(¶ms, &mut transcript_v, cm, proof);
|
||||
assert!(v);
|
||||
}
|
||||
}
|
||||
77
src/transcript.rs
Normal file
77
src/transcript.rs
Normal file
@@ -0,0 +1,77 @@
|
||||
/// transcript.rs file and adapted from https://github.com/arnaucube/nova-study
|
||||
use ark_ec::{AffineRepr, CurveGroup};
|
||||
use ark_ff::PrimeField;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use ark_crypto_primitives::sponge::poseidon::{PoseidonConfig, PoseidonSponge};
|
||||
use ark_crypto_primitives::sponge::{Absorb, CryptographicSponge};
|
||||
|
||||
pub struct Transcript<F: PrimeField + Absorb, C: CurveGroup>
|
||||
where
|
||||
<C as CurveGroup>::BaseField: Absorb,
|
||||
{
|
||||
// where F is the Constraint Field (eq. C::ScalarField)
|
||||
sponge: PoseidonSponge<F>,
|
||||
_c: PhantomData<C>,
|
||||
}
|
||||
impl<F: PrimeField + Absorb, C: CurveGroup> Transcript<F, C>
|
||||
where
|
||||
<C as CurveGroup>::BaseField: Absorb,
|
||||
{
|
||||
pub fn new(poseidon_config: &PoseidonConfig<F>) -> Self {
|
||||
let sponge = PoseidonSponge::<F>::new(poseidon_config);
|
||||
Transcript {
|
||||
sponge,
|
||||
_c: PhantomData,
|
||||
}
|
||||
}
|
||||
pub fn add(&mut self, v: &F) {
|
||||
self.sponge.absorb(&v);
|
||||
}
|
||||
pub fn add_vec(&mut self, v: &[F]) {
|
||||
self.sponge.absorb(&v);
|
||||
}
|
||||
pub fn add_point(&mut self, v: &C) {
|
||||
let v_affine = v.into_affine();
|
||||
let xy = v_affine.xy().unwrap(); // WIP
|
||||
self.sponge.absorb(&vec![xy.0, xy.1]);
|
||||
}
|
||||
pub fn get_challenge(&mut self) -> F {
|
||||
let c = self.sponge.squeeze_field_elements(1);
|
||||
self.add(&c[0]);
|
||||
c[0]
|
||||
}
|
||||
pub fn get_challenge_vec(&mut self, n: usize) -> Vec<F> {
|
||||
let c = self.sponge.squeeze_field_elements(n);
|
||||
self.sponge.absorb(&c);
|
||||
c
|
||||
}
|
||||
}
|
||||
|
||||
use ark_crypto_primitives::sponge::poseidon::find_poseidon_ark_and_mds;
|
||||
|
||||
// WARNING this is for test only
|
||||
pub fn poseidon_test_config<F: PrimeField>() -> PoseidonConfig<F> {
|
||||
let full_rounds = 8;
|
||||
let partial_rounds = 31;
|
||||
let alpha = 5;
|
||||
let rate = 2;
|
||||
|
||||
let (ark, mds) = find_poseidon_ark_and_mds::<F>(
|
||||
F::MODULUS_BIT_SIZE as u64,
|
||||
rate,
|
||||
full_rounds,
|
||||
partial_rounds,
|
||||
0,
|
||||
);
|
||||
|
||||
PoseidonConfig::new(
|
||||
full_rounds as usize,
|
||||
partial_rounds as usize,
|
||||
alpha,
|
||||
mds,
|
||||
ark,
|
||||
rate,
|
||||
1,
|
||||
)
|
||||
}
|
||||
17
src/utils.rs
Normal file
17
src/utils.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
use ark_ff::fields::PrimeField;
|
||||
|
||||
pub fn vec_add<F: PrimeField>(a: &Vec<F>, b: &[F]) -> Vec<F> {
|
||||
let mut r: Vec<F> = vec![F::zero(); a.len()];
|
||||
for i in 0..a.len() {
|
||||
r[i] = a[i] + b[i];
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
pub fn vec_scalar_mul<F: PrimeField>(vec: &[F], c: &F) -> Vec<F> {
|
||||
let mut result = vec![F::zero(); vec.len()];
|
||||
for (i, a) in vec.iter().enumerate() {
|
||||
result[i] = *a * c;
|
||||
}
|
||||
result
|
||||
}
|
||||
Reference in New Issue
Block a user