#![allow(non_snake_case)]
use std::ops::{Add, Mul};
use k256::{AffinePoint, ProjectivePoint, Scalar};
use k256::elliptic_curve::ops::Invert;
use k256::elliptic_curve::rand_core::{CryptoRng, RngCore};
use merlin::Transcript;
use serde::{Deserialize, Serialize};
use crate::util::*;
use crate::{circuit, transcript};
use crate::circuit::{ArithmeticCircuit, PartitionType};
#[derive(Clone, Debug)]
pub struct Witness {
pub x: Scalar,
pub s: Scalar,
pub m: Vec<Scalar>,
pub digits: Vec<Scalar>,
}
#[derive(Clone, Debug)]
pub struct Proof {
pub circuit_proof: circuit::Proof,
pub r: ProjectivePoint,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct SerializableProof {
pub circuit_proof: circuit::SerializableProof,
pub r: AffinePoint,
}
impl From<&SerializableProof> for Proof {
fn from(value: &SerializableProof) -> Self {
Proof {
circuit_proof: circuit::Proof::from(&value.circuit_proof),
r: ProjectivePoint::from(value.r),
}
}
}
impl From<&Proof> for SerializableProof {
fn from(value: &Proof) -> Self {
SerializableProof {
circuit_proof: circuit::SerializableProof::from(&value.circuit_proof),
r: value.r.to_affine(),
}
}
}
#[derive(Clone, Debug)]
pub struct ReciprocalRangeProofProtocol {
pub dim_nd: usize,
pub dim_np: usize,
pub g: ProjectivePoint,
pub g_vec: Vec<ProjectivePoint>,
pub h_vec: Vec<ProjectivePoint>,
pub g_vec_: Vec<ProjectivePoint>,
pub h_vec_: Vec<ProjectivePoint>,
}
impl ReciprocalRangeProofProtocol {
pub fn commit_value(&self, x: &Scalar, s: &Scalar) -> ProjectivePoint {
self.g.mul(x).add(&self.h_vec[0].mul(s))
}
pub fn commit_poles(&self, r: &[Scalar], s: &Scalar) -> ProjectivePoint {
self.h_vec[0].mul(s).add(&vector_mul(&self.h_vec[9..], r))
}
pub fn verify(&self, commitment: &ProjectivePoint, proof: Proof, t: &mut Transcript) -> bool {
transcript::app_point(b"reciprocal_commitment", commitment, t);
let e = transcript::get_challenge(b"reciprocal_challenge", t);
let circuit = self.make_circuit(e);
let circuit_commitment = commitment.add(&proof.r);
circuit.verify(&[circuit_commitment], t, proof.circuit_proof)
}
pub fn prove<R>(&self, commitment: &ProjectivePoint, witness: Witness, t: &mut Transcript, rng: &mut R) -> Proof
where
R: RngCore + CryptoRng
{
transcript::app_point(b"reciprocal_commitment", commitment, t);
let e = transcript::get_challenge(b"reciprocal_challenge", t);
let r = (0..self.dim_nd).map(|i|
witness.digits[i].add(&e).invert().unwrap()
).collect::<Vec<Scalar>>();
let r_blind = Scalar::generate_biased(rng);
let r_com = self.commit_poles(&r, &r_blind);
let mut v = vec![witness.x];
r.iter().for_each(|r_val| v.push(*r_val));
let w_l = witness.digits;
let w_r = r;
let w_o = witness.m;
let circuit = self.make_circuit(e);
let circuit_witness = circuit::Witness {
v: vec![v],
s_v: vec![witness.s.add(r_blind)],
w_l,
w_r,
w_o,
};
let circuit_commitment = circuit.commit(&circuit_witness.v[0], &circuit_witness.s_v[0]);
Proof {
circuit_proof: circuit.prove::<R>(&[circuit_commitment], circuit_witness, t, rng),
r: r_com,
}
}
#[inline(always)]
pub fn make_circuit(&self, e: Scalar) -> ArithmeticCircuit<impl Fn(PartitionType, usize) -> Option<usize> + '_>
{
let dim_nm = self.dim_nd;
let dim_no = self.dim_np;
let dim_nv = self.dim_nd + 1;
let dim_nl = dim_nv;
let dim_nw = self.dim_nd * 2 + self.dim_np;
let a_m = vec![Scalar::ONE; dim_nm];
let mut W_m = vec![vec![Scalar::ZERO; dim_nw]; dim_nm];
(0..dim_nm).for_each(|i| W_m[i][i + dim_nm] = minus(&e));
let a_l = vec![Scalar::ZERO; dim_nl];
let base = Scalar::from(self.dim_np as u32);
let mut W_l = vec![vec![Scalar::ZERO; dim_nw]; dim_nl];
(0..dim_nm).for_each(|i| W_l[0][i] = minus(&pow(&base, i)));
(0..dim_nm).for_each(|i|
(0..dim_nm).for_each(|j| W_l[i + 1][j + dim_nm] = Scalar::ONE)
);
(0..dim_nm).for_each(|i| W_l[i + 1][i + dim_nm] = Scalar::ZERO);
(0..dim_nm).for_each(|i|
(0..dim_no).for_each(|j|
W_l[i + 1][j + 2 * dim_nm] = minus(&(e.add(Scalar::from(j as u32)).invert_vartime().unwrap()))
)
);
let partition = |typ: PartitionType, index: usize| -> Option<usize>{
if typ == PartitionType::LL && index < self.dim_np {
Some(index)
} else {
None
}
};
ArithmeticCircuit {
dim_nm,
dim_no,
k: 1,
dim_nl,
dim_nv,
dim_nw,
g: self.g,
g_vec: self.g_vec.clone(),
h_vec: self.h_vec.clone(),
W_m,
W_l,
a_m,
a_l,
f_l: true,
f_m: false,
g_vec_: self.g_vec_.clone(),
h_vec_: self.h_vec_.clone(),
partition,
}
}
}