@ -0,0 +1,2 @@ |
|||
/target |
|||
/Cargo.lock |
@ -0,0 +1,19 @@ |
|||
[package] |
|||
name = "nova-study" |
|||
version = "0.0.1" |
|||
edition = "2021" |
|||
authors = ["arnaucube <root@arnaucube.com>"] |
|||
license = "GPL-3.0" |
|||
repository = "https://github.com/arnaucube/nova-study" |
|||
|
|||
[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" } |
|||
|
|||
[dev-dependencies] |
|||
ark-bn254 = { version = "0.4.0", default-features = false, features=["curve"] } |
@ -0,0 +1,122 @@ |
|||
use ark_ec::AffineRepr;
|
|||
use ark_std::{rand::RngCore, UniformRand};
|
|||
use std::marker::PhantomData;
|
|||
|
|||
use crate::transcript::Transcript;
|
|||
|
|||
pub struct Proof<C: AffineRepr> {
|
|||
R: C,
|
|||
t1: C::ScalarField,
|
|||
t2: C::ScalarField,
|
|||
}
|
|||
|
|||
pub struct Params<C: AffineRepr> {
|
|||
g: C,
|
|||
h: C,
|
|||
}
|
|||
|
|||
pub struct Pedersen<C: AffineRepr> {
|
|||
_phantom: PhantomData<C>,
|
|||
}
|
|||
|
|||
impl<C: AffineRepr> Pedersen<C> {
|
|||
pub fn commit<R: RngCore>(
|
|||
rng: &mut R,
|
|||
params: &Params<C>,
|
|||
v: &C::ScalarField,
|
|||
) -> (C, C::ScalarField) {
|
|||
let r = C::ScalarField::rand(rng);
|
|||
let cm: C = (params.g.mul(v) + params.h.mul(r)).into();
|
|||
(cm, r)
|
|||
}
|
|||
pub fn prove(
|
|||
params: &Params<C>,
|
|||
transcript: &mut Transcript<C::ScalarField>,
|
|||
cm: C,
|
|||
v: C::ScalarField,
|
|||
r: C::ScalarField,
|
|||
) -> Proof<C> {
|
|||
let s1 = transcript.get_challenge(b"s_1");
|
|||
let s2 = transcript.get_challenge(b"s_2");
|
|||
|
|||
let R: C = (params.g.mul(s1) + params.h.mul(s2)).into();
|
|||
|
|||
transcript.add(b"cm", &cm);
|
|||
transcript.add(b"R", &R);
|
|||
let c = transcript.get_challenge(b"c");
|
|||
|
|||
let t1 = s1 + v * c;
|
|||
let t2 = s2 + r * c;
|
|||
|
|||
Proof::<C> { R, t1, t2 }
|
|||
}
|
|||
|
|||
pub fn verify(
|
|||
params: &Params<C>,
|
|||
transcript: &mut Transcript<C::ScalarField>,
|
|||
cm: C,
|
|||
proof: Proof<C>,
|
|||
) -> bool {
|
|||
// s1, s2 just to match Prover's transcript
|
|||
transcript.get_challenge(b"s_1");
|
|||
transcript.get_challenge(b"s_2");
|
|||
|
|||
transcript.add(b"cm", &cm);
|
|||
transcript.add(b"R", &proof.R);
|
|||
let c = transcript.get_challenge(b"c");
|
|||
let lhs = proof.R + cm.mul(c);
|
|||
let rhs = params.g.mul(proof.t1) + params.h.mul(proof.t2);
|
|||
if lhs != rhs {
|
|||
return false;
|
|||
}
|
|||
true
|
|||
}
|
|||
}
|
|||
|
|||
pub struct Commitment<C: AffineRepr> {
|
|||
pub cm: C,
|
|||
pub r: C::ScalarField,
|
|||
}
|
|||
impl<C: AffineRepr> Commitment<C> {
|
|||
pub fn prove(
|
|||
self,
|
|||
params: &Params<C>,
|
|||
transcript: &mut Transcript<C::ScalarField>,
|
|||
v: C::ScalarField,
|
|||
) -> Proof<C> {
|
|||
Pedersen::<C>::prove(params, transcript, self.cm, v, self.r)
|
|||
}
|
|||
}
|
|||
|
|||
#[cfg(test)]
|
|||
mod tests {
|
|||
use super::*;
|
|||
use ark_bn254::{g1::G1Affine, Fr};
|
|||
use ark_ec::CurveGroup;
|
|||
use std::ops::Mul;
|
|||
|
|||
#[test]
|
|||
fn test_pedersen() {
|
|||
let mut rng = ark_std::test_rng();
|
|||
|
|||
// setup params
|
|||
let h_scalar = Fr::rand(&mut rng);
|
|||
let g: G1Affine = G1Affine::generator();
|
|||
let params: Params<G1Affine> = Params::<G1Affine> {
|
|||
g,
|
|||
h: g.mul(h_scalar).into_affine(),
|
|||
};
|
|||
|
|||
// init Prover's transcript
|
|||
let mut transcript_p: Transcript<Fr> = Transcript::<Fr>::new();
|
|||
// init Verifier's transcript
|
|||
let mut transcript_v: Transcript<Fr> = Transcript::<Fr>::new();
|
|||
|
|||
let v = Fr::rand(&mut rng);
|
|||
|
|||
let (cm, r) = Pedersen::commit(&mut rng, ¶ms, &v);
|
|||
let proof = Pedersen::prove(¶ms, &mut transcript_p, cm, v, r);
|
|||
let v = Pedersen::verify(¶ms, &mut transcript_v, cm, proof);
|
|||
assert!(v);
|
|||
}
|
|||
}
|
@ -0,0 +1,32 @@ |
|||
use ark_ff::PrimeField;
|
|||
use ark_serialize::CanonicalSerialize;
|
|||
use merlin::Transcript as MerlinTranscript;
|
|||
use std::marker::PhantomData;
|
|||
|
|||
// This Transcript approach is a modified version from https://github.com/arkworks-rs/gemini ,
|
|||
// using Merlin transcript (https://merlin.cool).
|
|||
pub struct Transcript<F: PrimeField> {
|
|||
phantom: PhantomData<F>,
|
|||
transcript: MerlinTranscript,
|
|||
}
|
|||
|
|||
impl<F: PrimeField> Transcript<F> {
|
|||
pub fn new() -> Self {
|
|||
Self {
|
|||
phantom: PhantomData::default(),
|
|||
transcript: MerlinTranscript::new(b"transcript"),
|
|||
}
|
|||
}
|
|||
pub fn add<S: CanonicalSerialize>(&mut self, label: &'static [u8], r: &S) {
|
|||
let mut msg = Vec::new();
|
|||
r.serialize_uncompressed(&mut msg).unwrap();
|
|||
self.transcript.append_message(label, &msg);
|
|||
}
|
|||
pub fn get_challenge(&mut self, label: &'static [u8]) -> F {
|
|||
let mut bytes = [0u8; 64];
|
|||
self.transcript.challenge_bytes(label, &mut bytes);
|
|||
let challenge = F::from_le_bytes_mod_order(bytes.as_ref());
|
|||
self.add(b"get challenge", &challenge);
|
|||
challenge
|
|||
}
|
|||
}
|