libbolt/src/ped92.rs

426 lines
14 KiB
Rust

// ped92.rs
use rand::{Rng, AsByteSliceMut};
use pairing::{Engine, CurveProjective};
use ff::{Rand, Field, PrimeField};
use std::fmt;
use util::is_vec_g1_equal;
use serde::{Serialize, Deserialize};
use util;
#[derive(Clone)]
pub struct CSParams<E: Engine> {
pub g: E::G1,
pub h: E::G1,
}
#[derive(Clone, Serialize, Deserialize)]
#[serde(bound(serialize = "<E as pairing::Engine>::G1: serde::Serialize"))]
#[serde(bound(deserialize = "<E as pairing::Engine>::G1: serde::Deserialize<'de>"))]
pub struct Commitment<E: Engine> {
pub c: E::G1,
}
impl<E: Engine> PartialEq for Commitment<E> {
fn eq(&self, other: &Commitment<E>) -> bool {
self.c == other.c
}
}
#[derive(Clone, Serialize, Deserialize)]
#[serde(bound(serialize = "<E as pairing::Engine>::G1: serde::Serialize"))]
#[serde(bound(deserialize = "<E as pairing::Engine>::G1: serde::Deserialize<'de>"))]
pub struct CSMultiParams<E: Engine> {
pub pub_bases: Vec<E::G1>
}
impl<E: Engine> PartialEq for CSMultiParams<E> {
fn eq(&self, other: &CSMultiParams<E>) -> bool {
is_vec_g1_equal::<E>(&self.pub_bases, &other.pub_bases)
}
}
impl<E: Engine> CSMultiParams<E> {
pub fn from_slice<'de>(ser_gs: &'de [u8], g_len: usize, num_elems: usize) -> Self
where <E as pairing::Engine>::G1: serde::Deserialize<'de>
{
let mut pub_bases: Vec<E::G1> = Vec::new();
let mut start_pos = 0;
let mut end_pos = g_len;
for _ in 0 .. num_elems {
let g: E::G1 = serde_json::from_slice(&ser_gs[start_pos .. end_pos]).unwrap();
start_pos = end_pos;
end_pos += g_len;
pub_bases.push(g);
}
return CSMultiParams { pub_bases};
}
}
impl<E: Engine> fmt::Display for CSMultiParams<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut y_str = String::new();
let mut i = 0;
for y in self.pub_bases.iter() {
y_str = format!("{}\n{} => {}", y_str, i, y);
i += 1;
}
write!(f, "CSMultiParams : (\n{}\n)", y_str)
}
}
impl<E: Engine> fmt::Display for Commitment<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Commitment : (c={})", &self.c)
}
}
impl<E: Engine> CSParams<E> {
/*
Implements the setup algorithm for the Pedersen92 commitment scheme
*/
pub fn setup<R: Rng>(rng: &mut R) -> Self {
let g = E::G1::rand(rng);
let h = E::G1::rand(rng);
CSParams { g, h }
}
/*
commit(pk, msg) -> cm where
- pk is the public key generated from setup()
- msg is the message structure for the commitment scheme
- cm is the output commitment message for the given message
*/
pub fn commit<R: Rng>(&self, rng: &mut R, m: E::Fr, R: Option<E::Fr>) -> Commitment<E> {
let r = R.unwrap_or(E::Fr::rand(rng));
// c = g^m * h^r
let mut c = self.g.clone();
c.mul_assign(m.clone());
let mut h = self.h.clone();
h.mul_assign(r.clone());
c.add_assign(&h);
Commitment { c }
}
/*
decommit(csp, cm, msg) -> bool where
- cm is the commitment
- m is the message to validate
- outputs T/F for whether the cm is a valid commitment to the msg
*/
pub fn decommit(&self, cm: &Commitment<E>, m: &E::Fr, r: &E::Fr) -> bool {
let mut dm = self.g.clone();
dm.mul_assign(m.clone());
let mut h = self.h.clone();
h.mul_assign(r.clone());
dm.add_assign(&h);
dm == cm.c
}
}
impl<E: Engine> CSMultiParams<E> {
/*
Implements the setup algorithm for the Pedersen92 commitment scheme over
a vector of messages of length len.
*/
pub fn setup_gen_params<R: Rng>(rng: &mut R, len: usize) -> Self {
let mut p: Vec<E::G1> = Vec::new();
// 1 extra base element for the random parameter
for _i in 0..len + 1 {
p.push(E::G1::rand(rng));
}
CSMultiParams { pub_bases: p }
}
pub fn commit(&self, x: &Vec<E::Fr>, r: &E::Fr) -> Commitment<E> {
// c = g1^m1 * ... * gn^mn * h^r
let mut c = self.pub_bases[0].clone();
let p_len = self.pub_bases.len();
c.mul_assign(r.clone());
//println!("commit => x.len = {}, p.len = {}", x.len(), p_len);
for i in 0..x.len() {
if (i < p_len) {
let mut basis = self.pub_bases[i + 1];
basis.mul_assign(x[i]);
c.add_assign(&basis);
}
}
Commitment { c }
}
pub fn extend_commit(&self, com: &Commitment<E>, x: &E::Fr) -> Commitment<E> {
// c = com * gn+1 ^ x
let len = self.pub_bases.len();
let mut c = self.pub_bases[len-1].clone();
c.mul_assign(x.clone());
c.add_assign(&com.c);
return Commitment { c };
}
pub fn remove_commit(&self, com: &Commitment<E>, x: &E::Fr) -> Commitment<E> {
// c = com * gn+1 ^ x
let len = self.pub_bases.len();
let mut c = self.pub_bases[len-1].clone();
let xx = x.clone();
c.mul_assign(xx);
c.negate();
c.add_assign(&com.c);
return Commitment { c };
}
pub fn decommit(&self, cm: &Commitment<E>, x: &Vec<E::Fr>, r: &E::Fr) -> bool {
let l = x.len();
// pub_base[0] => h, x[0] => r
let mut dc = self.pub_bases[0].clone();
dc.mul_assign(r.clone());
for i in 0..l {
let mut basis = self.pub_bases[i+1];
basis.mul_assign(x[i]);
dc.add_assign(&basis);
}
return dc == cm.c;
}
}
#[derive(Clone, Serialize, Deserialize, Debug)]
#[serde(bound(serialize = "<E as ff::ScalarEngine>::Fr: serde::Serialize, \
<E as pairing::Engine>::G1: serde::Serialize, \
<E as pairing::Engine>::G2: serde::Serialize"
))]
#[serde(bound(deserialize = "<E as ff::ScalarEngine>::Fr: serde::Deserialize<'de>, \
<E as pairing::Engine>::G1: serde::Deserialize<'de>, \
<E as pairing::Engine>::G2: serde::Deserialize<'de>"
))]
pub struct CommitmentProof<E: Engine> {
pub T: E::G1,
pub z: Vec<E::Fr>,
}
impl<E: Engine> CommitmentProof<E> {
pub fn new<R: Rng>(csprng: &mut R, com_params: &CSMultiParams<E>, com: &E::G1, wallet: &Vec<E::Fr>, r: &E::Fr, reveal_index: &Vec<usize>) -> Self {
let mut rt = Vec::new();
for i in 0..wallet.len() + 1 {
if reveal_index.contains(&i) {
rt.push(E::Fr::zero());
} else {
rt.push(E::Fr::rand(csprng));
}
}
let (Tvals, t) = CommitmentProof::<E>::prove_commitment::<R>(csprng, com_params, wallet, Some(rt));
// compute the challenge
let x: Vec<E::G1> = vec![Tvals, com.clone()];
let challenge = util::hash_g1_to_fr::<E>(&x);
// compute the response
CommitmentProof::<E>::prove_response(wallet, r, Tvals, &t, &challenge)
}
pub fn prove_commitment<R: Rng>(csprng: &mut R, com_params: &CSMultiParams<E>, wallet: &Vec<E::Fr>, tOptional: Option<Vec<E::Fr>>) -> (E::G1, Vec<E::Fr>) {
let mut Tvals = E::G1::zero();
assert!(wallet.len() <= com_params.pub_bases.len());
let mut t = tOptional.unwrap_or(Vec::<E::Fr>::with_capacity(wallet.len() + 1));
// aspects of wallet being revealed
for i in 0..wallet.len() + 1 {
if t.len() == i {
t.push(E::Fr::rand(csprng));
}
let ti = t[i].clone();
let mut gt = com_params.pub_bases[i].clone();
gt.mul_assign(ti.into_repr());
Tvals.add_assign(&gt);
}
(Tvals, t)
}
pub fn prove_response(wallet: &Vec<E::Fr>, r: &E::Fr, Tvals: E::G1, t: &Vec<E::Fr>, challenge: &E::Fr) -> CommitmentProof<E> {
let mut z: Vec<E::Fr> = Vec::new();
let mut z0 = r.clone();
z0.mul_assign(&challenge);
z0.add_assign(&t[0]);
z.push(z0);
for i in 1..t.len() {
let mut zi = wallet[i - 1].clone();
zi.mul_assign(&challenge);
zi.add_assign(&t[i]);
z.push(zi);
}
CommitmentProof {
T: Tvals, // commitment challenge
z: z, // response values
}
}
pub fn verify_proof(&self, com_params: &CSMultiParams<E>, com: &<E as Engine>::G1, challenge: &E::Fr, revealOption: Option<Vec<Option<E::Fr>>>) -> bool {
let mut comc = com.clone();
let T = self.T.clone();
comc.mul_assign(challenge.into_repr());
comc.add_assign(&T);
let mut x = E::G1::zero();
let reveal = revealOption.unwrap_or(vec!{});
let mut revealBool = true;
for i in 0..self.z.len() {
let mut base = com_params.pub_bases[i].clone();
base.mul_assign(self.z[i].into_repr());
x.add_assign(&base);
if reveal.len() > i && reveal[i].is_some() {
let mut el = reveal[i].unwrap();
el.mul_assign(&challenge.clone());
revealBool = revealBool && self.z[i] == el;
}
}
revealBool && comc == x
}
}
#[cfg(test)]
mod tests {
use super::*;
use pairing::bls12_381::{Bls12, Fr, G1};
use rand::thread_rng;
use ff::Field;
use wallet::Wallet;
#[test]
fn commit_one_message_works() {
let rng = &mut thread_rng();
let csp = CSParams::<Bls12>::setup(rng);
let m1 = Fr::rand(rng);
let mut m2 = m1.clone();
m2.add_assign(&Fr::one());
let r = Fr::rand(rng);
let c = csp.commit(rng, m1, Some(r));
assert_eq!(csp.decommit(&c, &m1, &r), true);
assert_eq!(csp.decommit(&c, &m2, &r), false);
}
#[test]
fn commit_n_message_works() {
let rng = &mut thread_rng();
let len = 3;
let csp = CSMultiParams::<Bls12>::setup_gen_params(rng, len);
let mut m: Vec<Fr> = Vec::new();
for _i in 0..len {
m.push(Fr::rand(rng));
}
let r = Fr::rand(rng);
let c = csp.commit(&m, &r);
assert_eq!(csp.decommit(&c, &m, &r), true);
let mut r1 = r.clone();
r1.add_assign(&Fr::one());
assert_eq!(csp.decommit(&c, &m, &r1), false);
}
#[test]
fn commit_variable_messages_works() {
let rng = &mut thread_rng();
let len = 5;
let csp = CSMultiParams::<Bls12>::setup_gen_params(rng, len);
let mut m1: Vec<Fr> = Vec::new();
for _i in 0..len-1 {
m1.push(Fr::rand(rng));
}
let extra_m = Fr::rand(rng);
let r = Fr::rand(rng);
let c1 = csp.commit(&m1, &r);
assert_eq!(csp.decommit(&c1, &m1, &r), true);
let mut r1 = r.clone();
r1.add_assign(&Fr::one());
assert_eq!(csp.decommit(&c1, &m1, &r1), false);
// let's add another message
let mut m2 = m1.clone();
m2.push(extra_m);
let c2 = csp.commit(&m2, &r);
assert_eq!(csp.decommit(&c2, &m2, &r), true);
}
#[test]
fn test_csp_basic_serialize() {
let rng = &mut rand::thread_rng();
let len = 5;
let csp = CSMultiParams::<Bls12>::setup_gen_params(rng, len);
let serialized = serde_json::to_string(&csp).unwrap();
let _csp_des: CSMultiParams<Bls12> = serde_json::from_str(&serialized).unwrap();
}
#[test]
fn test_proof_commitment() {
let rng = &mut rand::thread_rng();
let channelId = Fr::rand(rng);
let wpk = Fr::rand(rng);
let t = Fr::rand(rng);
let bc = rng.gen_range(100, 1000);
let bm = rng.gen_range(100, 1000);
let wallet = Wallet::<Bls12> { channelId: channelId, wpk: wpk, bc: bc, bm: bm, close: None };
let comParams = CSMultiParams::setup_gen_params(rng, 4);
let com = comParams.commit(&wallet.as_fr_vec().clone(), &t);
let proof = CommitmentProof::<Bls12>::new(rng, &comParams, &com.c, &wallet.as_fr_vec(), &t, &vec!{});
let xvec: Vec<G1> = vec![proof.T.clone(), com.c];
let challenge = util::hash_g1_to_fr::<Bls12>(&xvec);
assert_eq!(proof.verify_proof(&comParams, &com.c, &challenge, None), true);
}
#[test]
fn test_cs_multiparam_serialization() {
let mut vec: Vec<u8> = Vec::new();
let bin_g1= vec![132, 83, 99, 124, 75, 72, 15, 109, 12, 94, 84, 103, 1, 58, 160, 232, 190, 23, 119, 195, 112, 161, 152, 141, 178, 29, 141, 61, 227, 246, 215, 157, 140, 190, 100, 18, 248, 141, 57, 222, 12, 209, 191, 158, 143, 155, 87, 255];
let bin_g2 = vec![140, 16, 244, 244, 135, 28, 18, 94, 46, 64, 233, 195, 218, 147, 238, 170, 46, 164, 50, 92, 234, 117, 61, 158, 64, 226, 153, 38, 127, 168, 49, 125, 177, 183, 74, 164, 138, 128, 168, 84, 137, 67, 21, 179, 124, 88, 194, 239];
let bin_g3 = vec![147, 174, 242, 238, 231, 127, 9, 120, 16, 9, 191, 238, 60, 57, 106, 34, 198, 62, 28, 183, 77, 170, 27, 116, 36, 75, 242, 26, 242, 23, 213, 31, 186, 21, 141, 219, 59, 104, 247, 118, 56, 95, 183, 124, 103, 83, 93, 154];
let ser_g1 = util::encode_as_hexstring(&bin_g1);
let ser_g2 = util::encode_as_hexstring(&bin_g2);
let ser_g3 = util::encode_as_hexstring(&bin_g3);
let str_g1 = ser_g1.as_bytes();
let str_g2 = ser_g2.as_bytes();
let str_g3 = ser_g3.as_bytes();
vec.extend(str_g1);
vec.extend(str_g2);
vec.extend(str_g3);
let rec_csparams = CSMultiParams::<Bls12>::from_slice(&vec.as_slice(), str_g1.len(), 3);
println!("CS params: {:?}", rec_csparams.pub_bases);
let ser_cs = serde_json::to_string(&rec_csparams).unwrap();
println!("Serialized: {:}", ser_cs);
let rec_g1_str = serde_json::to_string(&rec_csparams.pub_bases[0]).unwrap();
assert_eq!(rec_g1_str, "\"8453637c4b480f6d0c5e5467013aa0e8be1777c370a1988db21d8d3de3f6d79d8cbe6412f88d39de0cd1bf9e8f9b57ff\"");
let rec_g2_str = serde_json::to_string(&rec_csparams.pub_bases[1]).unwrap();
assert_eq!(rec_g2_str, "\"8c10f4f4871c125e2e40e9c3da93eeaa2ea4325cea753d9e40e299267fa8317db1b74aa48a80a854894315b37c58c2ef\"");
let rec_g3_str = serde_json::to_string(&rec_csparams.pub_bases[2]).unwrap();
assert_eq!(rec_g3_str, "\"93aef2eee77f09781009bfee3c396a22c63e1cb74daa1b74244bf21af217d51fba158ddb3b68f776385fb77c67535d9a\"");
}
}