Added new mimc hash with calculation proof.

This commit is contained in:
Fritz Schmid 2024-01-28 19:38:09 +01:00
parent ab1e399768
commit 0fbfc57a9a
7 changed files with 1152 additions and 139 deletions

712
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,21 @@ futures = "*"
reqwest ={ version = "*", features = ["json"]}
rocket_okapi = { version = "0.8.0-alpha-1", features = ["swagger", "rapidoc"] }
arkworks-mimc = { version = "0.3.0", features = ["mimc-7-91-bls12-381","r1cs"] }
ark-ff = { version = "^0.3.0", default-features = false }
ark-bls12-381 = "0.3.0"
ark-bls12-377 = "0.3.0"
ark-crypto-primitives = "0.3.0"
ark-std = "0.3.0"
ark-relations = "0.3.0"
ark-r1cs-std = "0.3.0"
ark-groth16 = "0.3.0"
ark-serialize = "0.3.0"
ark-ec = "0.3.0"
subtle = "*"
# Fixes compilation on windows
tokio = "1.28.0"
[[bin]]
name = "cryptoservice"

View File

@ -1,3 +1,6 @@
use ark_bls12_381::Bls12_381;
use ark_groth16::PreparedVerifyingKey;
use ark_groth16::ProvingKey;
use bls12_381::*;
use group::Group;
use crate::utils;
@ -28,35 +31,43 @@ pub struct ServerState{
r: Scalar,
pub n: Scalar,
p: G2Projective,
pw: String,
ps: Scalar,
pw: String
}
impl ServerState {
fn new(username: &String, password: &String) -> ServerState{
fn new(username: &String, password: &String,pk: &ProvingKey<Bls12_381>) -> (ServerState,Vec<u8>){
let r = utils::random_scalar();
let n = utils::random_scalar();
let username = username.to_owned();
let to_be_hashed = username + password;
let tempr = utils::hash_string_to_scalar(to_be_hashed);
let p = G2Affine::generator() * tempr * r;
ServerState{r,n,p,pw: password.to_owned()}
let (hash_scalar,hash_proof) = proofs::generate_hash_proof(username, password, &n, &r, pk);
let p = G2Affine::generator() * hash_scalar;
// let username = username.to_owned();
// let to_be_hashed = username + password;
// let tempr = utils::hash_string_to_scalar(to_be_hashed);
// let p = G2Affine::generator() * tempr * r;
(ServerState{r,n,p,ps:hash_scalar,pw: password.to_owned()},hash_proof)
}
fn from_nonce(username: &String, password: &String, nonce: &Scalar) -> ServerState{
fn from_nonce(username: &String, password: &String, nonce: &Scalar,pk: &ProvingKey<Bls12_381>) -> (ServerState,Vec<u8>){
let r = utils::random_scalar();
let username = username.to_owned();
let to_be_hashed = username + password;
let tempr = utils::hash_string_to_scalar(to_be_hashed);
let p = G2Affine::generator() * tempr * r;
ServerState{r,n: nonce.clone(),p,pw: password.to_owned()}
let (hash_scalar,hash_proof) = proofs::generate_hash_proof(username, password, &nonce, &r, pk);
let p = G2Affine::generator() * hash_scalar;
// let username = username.to_owned();
// let to_be_hashed = username + password;
// let tempr = utils::hash_string_to_scalar(to_be_hashed);
// let p = G2Affine::generator() * tempr * r;
(ServerState{r,n: nonce.clone(),p,ps:hash_scalar,pw: password.to_owned()},hash_proof)
}
}
#[serde_as]
#[derive(Serialize, Deserialize, JsonSchema,Clone,Copy,Debug)]
#[derive(Serialize, Deserialize, JsonSchema,Clone,Debug)]
pub struct RatelimiterRequest{
#[serde_as(as = "serializers::SerializeScalar")]
#[schemars(with = "String")]
@ -64,6 +75,12 @@ pub struct RatelimiterRequest{
#[serde_as(as = "serializers::SerializeG2")]
#[schemars(with = "String")]
p: G2Projective,
#[serde_as(as = "serializers::SerializeScalar")]
#[schemars(with = "String")]
ps: Scalar,
#[serde_as(as = "serde_with::base64::Base64")]
#[schemars(with = "String")]
hash_proof: Vec<u8>
}
#[serde_as]
@ -118,28 +135,42 @@ pub struct SetKeyHelper{
}
pub fn phe_init(username: &String, password: &String) -> (ServerState,RatelimiterRequest){
let ss = ServerState::new(username,password);
let rr = RatelimiterRequest{n:ss.n,p:ss.p};
pub fn phe_init(username: &String, password: &String,pk: &ProvingKey<Bls12_381>) -> (ServerState,RatelimiterRequest){
let (ss,hash_proof) = ServerState::new(username,password,pk);
let rr = RatelimiterRequest{n:ss.n,p:ss.p,hash_proof,ps:ss.ps};
return (ss,rr)
}
pub fn phe_init_decrypt(username: &String, password: &String,n: &Scalar) -> (ServerState,RatelimiterRequest){
let ss = ServerState::from_nonce(username,password,n);
let rr = RatelimiterRequest{n:ss.n,p:ss.p};
pub fn phe_init_decrypt(username: &String, password: &String,n: &Scalar,pk: &ProvingKey<Bls12_381>) -> (ServerState,RatelimiterRequest){
let (ss,hash_proof) = ServerState::from_nonce(username,password,n,pk);
let rr = RatelimiterRequest{n:ss.n,p:ss.p,hash_proof,ps:ss.ps};
return (ss,rr)
}
pub fn phe_ratelimiter(private_key: &Scalar, request: &RatelimiterRequest,pp: &PublicParameters) -> RatelimiterResponse {
pub fn phe_ratelimiter(private_key: &Scalar, request: &RatelimiterRequest,pp: &PublicParameters,pvk: &PreparedVerifyingKey<Bls12_381>) -> Result<RatelimiterResponse,String> {
// check if request.p = G2Affine::generator() * hash_proof
if (G2Affine::generator() * request.ps) != request.p{
return Err("Invalid hash proof. Hash scalar and Point not matching.".to_string());
}
//verify hash proof
let result = proofs::validate_hash_proof(&request.ps,&request.hash_proof,&pvk);
if !result{
return Err("Invalid hash proof.".to_string());
}
let n = request.n;
let u = pairing(&G1Affine::from(G1Affine::generator() * n) , &G2Affine::from(request.p));
let value = u*private_key;
let proof = proofs::SameDLogProofPublic{g:pp.gt_gen,h:u,y1:pp.ratelimiter_public_key,y2:value}.proof(&private_key);
RatelimiterResponse{proof,u:value}
Ok(RatelimiterResponse{proof,u:value})
}
pub fn phe_enc_finish_t(msg: &Vec<u8>,pp: &Vec<PublicParameters>,response: &Vec<RatelimiterResponse>,ss:&ServerState,n: i64) -> Result<EncryptedMessage,String>{
@ -421,12 +452,14 @@ fn test_core_t(n:i64,t:i64){
assert_eq!(pp_key,generator*realkey,"Public keys do not match");
let (pk,vk,pvk) = proofs::setup_hash_proof();
let start = Instant::now();
let (ss,request) = phe_init(&"test".to_string(),&"test".to_string());
let (ss,request) = phe_init(&"test".to_string(),&"test".to_string(),&pk);
println!("{:.2?} phe_init",start.elapsed());
let responses = (0..t as usize).into_par_iter().map(|i|{
let response = phe_ratelimiter(&rlkeys[i],&request,&pps[i]);
let response = phe_ratelimiter(&rlkeys[i],&request,&pps[i],&pvk).unwrap();
response
}).collect::<Vec<_>>();
@ -434,10 +467,10 @@ fn test_core_t(n:i64,t:i64){
let res = phe_enc_finish_t(&msg,&pps,&responses,&ss,n).unwrap();
println!("{:.2?} phe_enc_finish_t",start.elapsed());
let (ss,request) = phe_init_decrypt(&"test".to_string(),&"test".to_string(),&request.n);
let (ss,request) = phe_init_decrypt(&"test".to_string(),&"test".to_string(),&request.n, &pk);
let responses = (0..t as usize).into_par_iter().map(|i|{
let response = phe_ratelimiter(&rlkeys[i],&request,&pps[i]);
let response = phe_ratelimiter(&rlkeys[i],&request,&pps[i],&pvk).unwrap();
response
}).collect::<Vec<_>>();
@ -459,14 +492,16 @@ fn test_core_k() {
ratelimiter_public_key: public_key
};
let (pk,vk,pvk) = proofs::setup_hash_proof();
let start = Instant::now();
let (ss,request) = phe_init(&"test".to_string(),&"test".to_string());
let (ss,request) = phe_init(&"test".to_string(),&"test".to_string(),&pk);
println!("{:.2?} phe_init",start.elapsed());
let response = phe_ratelimiter(&key,&request,&pp);
let response = phe_ratelimiter(&key,&request,&pp,&pvk).unwrap();
let start = Instant::now();
for _i in 0..100{
let response = phe_ratelimiter(&key,&request,&pp);
let response = phe_ratelimiter(&key,&request,&pp,&pvk).unwrap();
}
println!("{:.2?} phe_ratelimiter",start.elapsed()/1000);
@ -477,9 +512,9 @@ fn test_core_k() {
}
println!("{:.2?} phe_enc_finish",start.elapsed()/1000);
let (ss,request) = phe_init_decrypt(&"test".to_string(),&"test".to_string(),&ciphertext.n);
let (ss,request) = phe_init_decrypt(&"test".to_string(),&"test".to_string(),&ciphertext.n, &pk);
let response = phe_ratelimiter(&key,&request,&pp);
let response = phe_ratelimiter(&key,&request,&pp,&pvk).unwrap();
let expected = phe_dec_finish_simple(&ciphertext,&pp,&response,&ss).unwrap();
let start = Instant::now();

View File

@ -4,9 +4,12 @@ extern crate bls12_381;
extern crate rand;
use std::sync::RwLock;
use ark_bls12_381::Bls12_381;
use ark_groth16::PreparedVerifyingKey;
use bls12_381::pairing;
use bls12_381::G2Affine;
use std::sync::Mutex;
use ophe::proofs;
use ophe::proofs::HashProof;
use std::sync::Arc;
use rocket_okapi::settings::UrlObject;
use rocket_okapi::{openapi, openapi_get_routes, rapidoc::*, swagger_ui::*};
@ -22,23 +25,35 @@ use bls12_381::Scalar;
use bls12_381::G1Affine;
fn make_public_parameters(key: Scalar) -> CryptoserviceState{
let generator = pairing(&G1Affine::generator(), &G2Affine::generator());
let public_key = generator * key;
let pp = core::PublicParameters{ratelimiter_public_key:public_key,gt_gen:generator};
CryptoserviceState{key,pp}
let mut rng = OsRng::default();
let test: HashProof = HashProof {
pw_point: None,
nonce_point: None,
random_r: None,
};
let (pk, vk,pvk) = proofs::setup_hash_proof();
CryptoserviceState{key,pp,hashproof_pvk:pvk}
}
struct CryptoserviceState {
key: Scalar,
pp: core::PublicParameters,
hashproof_pvk: PreparedVerifyingKey<Bls12_381>,
}
type CryptoserviceStatePointer = Arc<RwLock<CryptoserviceState>>;
use rand_core::{RngCore, OsRng};
#[rocket::main]
async fn main() {
@ -80,15 +95,14 @@ async fn main() {
#[openapi()]
#[post("/phe_help",format = "json", data = "<request>")]
fn phe_help(request: Json<RatelimiterRequest>,c_state: &State<CryptoserviceStatePointer>) -> Json<RatelimiterResponse> {
fn phe_help(request: Json<RatelimiterRequest>,c_state: &State<CryptoserviceStatePointer>) -> Result<Json<RatelimiterResponse>,String> {
let (key,pp) = {
let (key,pp,pvk) = {
let c_state = c_state.read().unwrap();
(c_state.key.clone(),c_state.pp.clone())
(c_state.key.clone(),c_state.pp.clone(),c_state.hashproof_pvk.clone())
};
Json(core::phe_ratelimiter(&key,&request,&pp))
Ok(Json(core::phe_ratelimiter(&key,&request,&pp,&pvk)?))
}
#[openapi()]

View File

@ -1,5 +1,5 @@
#![allow(dead_code)]
mod proofs;
pub mod proofs;
pub mod utils;
pub mod shamir;
pub mod core;

View File

@ -3,11 +3,15 @@
extern crate bls12_381;
extern crate rand;
use ark_bls12_381::Bls12_381;
use ark_groth16::PreparedVerifyingKey;
use ark_groth16::ProvingKey;
use bls12_381::G2Affine;
use bls12_381::Gt;
use bls12_381::Scalar;
use bls12_381::pairing;
use bls12_381::G1Affine;
use ophe::proofs;
use rocket::request;
use std::time::Duration;
use crate::core::EncryptedMessage;
@ -43,6 +47,7 @@ struct OpheState {
n: i64,
t: i64,
pk: Gt,
hash_proof_vk: ProvingKey<Bls12_381>,
}
#[derive(Serialize,Deserialize,JsonSchema)]
@ -77,7 +82,7 @@ fn serialize_failed(_req: &Request) -> String {
#[rocket::main]
async fn main() {
let cryptoservice_urls = vec!["http://localhost:9001","http://localhost:9002","http://localhost:9003"];
let cryptoservice_urls = vec!["http://localhost:9001","http://localhost:9002"];
let n = cryptoservice_urls.len();
let t = n;
let rl_key = ophe::utils::random_scalar();
@ -102,7 +107,9 @@ async fn main() {
assert_eq!(pp_key,rl_public_key,"Public keys do not match");
let o_state = OpheState{pps,n: n as i64,t: t as i64, pk: pp_key};
let hash_proof_setup = proofs::setup_hash_proof();
let o_state = OpheState{pps,n: n as i64,t: t as i64, pk: pp_key, hash_proof_vk: hash_proof_setup.0};
println!("Received public parameters from crytoservice");
@ -143,7 +150,7 @@ async fn main() {
#[openapi()]
#[post("/encrypt",format = "json", data = "<request>")]
async fn encrypt(request: Json<EncryptRequest>,o_state: &State<OpheState>) -> Result<Json<EncryptedMessage>,(Status, Json<String>)> {
let (ss,request1) = core::phe_init(&request.username,&request.password);
let (ss,request1) = core::phe_init(&request.username,&request.password,&o_state.hash_proof_vk);
let mut msg = request.data.clone().into_bytes();
@ -165,7 +172,7 @@ async fn encrypt(request: Json<EncryptRequest>,o_state: &State<OpheState>) -> Re
#[openapi()]
#[post("/decrypt",format = "json", data = "<request>")]
async fn decrypt(request: Json<DecryptRequest>,o_state: &State<OpheState>) -> Result<Json<String>,(Status, Json<String>)> {
let (ss,request1) = core::phe_init_decrypt(&request.username,&request.password,&request.ciphertext.n);
let (ss,request1) = core::phe_init_decrypt(&request.username,&request.password,&request.ciphertext.n,&o_state.hash_proof_vk);
let responses = get_ratelimiter_reponses(&request1,&o_state.pps).await.map_err(|x| {(Status::InternalServerError,Json("Decryption failed: ".to_string()+&x))})?;

View File

@ -1,23 +1,48 @@
use bls12_381::*;
use crate::utils;
use std::convert::TryInto;
use std::time::Instant;
use crate::serializers;
use serde::{Deserialize, Serialize};
use rocket_okapi::okapi::schemars;
use rocket_okapi::okapi::schemars::JsonSchema;
use serde_with::serde_as;
use crate::utils;
use ark_bls12_381::Bls12_381;
use ark_crypto_primitives::CircuitSpecificSetupSNARK;
use ark_crypto_primitives::SNARK;
use ark_ff::BigInteger;
use ark_ff::Fp2;
use ark_ff::Fp384;
use ark_ff::Fp384Parameters;
use ark_groth16::PreparedVerifyingKey;
use ark_groth16::Proof;
use ark_groth16::ProvingKey;
use ark_groth16::VerifyingKey;
use ark_groth16::prepare_verifying_key;
use ark_groth16::Groth16;
use ark_r1cs_std::alloc::AllocationMode;
use ark_r1cs_std::eq::EqGadget;
use ark_r1cs_std::fields::FieldVar;
use ark_relations::lc;
use ark_relations::r1cs::ConstraintSynthesizer;
use ark_relations::r1cs::ConstraintSystem;
use ark_relations::r1cs::ConstraintSystemRef;
use ark_relations::r1cs::SynthesisError;
use ark_serialize::CanonicalSerializeWithFlags;
use arkworks_mimc::constraints::MiMCVar;
use bls12_381::*;
#[cfg(test)]
use group::Group;
use rand_core::OsRng;
use rocket_okapi::okapi::schemars;
use rocket_okapi::okapi::schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
pub struct SameDLogProofPublic {
pub g: Gt,
pub h: Gt,
pub y1: Gt,
pub y2: Gt,
pub g: Gt,
pub h: Gt,
pub y1: Gt,
pub y2: Gt,
}
impl SameDLogProofPublic{
impl SameDLogProofPublic {
pub fn new(g: Gt, h: Gt, x: Scalar) -> Self {
SameDLogProofPublic {
g,
@ -27,7 +52,7 @@ impl SameDLogProofPublic{
}
}
pub fn proof(&self,x: &Scalar) -> SameDLogProof{
pub fn proof(&self, x: &Scalar) -> SameDLogProof {
let r = utils::random_scalar();
let c = utils::hash_gt_to_scalar(&[&self.g, &self.h, &self.y1, &self.y2]);
let t = r - x * c;
@ -39,9 +64,8 @@ impl SameDLogProofPublic{
}
}
#[serde_as]
#[derive(Eq,PartialEq,Debug,Serialize,Deserialize,JsonSchema)]
#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, JsonSchema)]
pub struct SameDLogProof {
#[serde_as(as = "serializers::SerializeGt")]
#[schemars(with = "String")]
@ -54,15 +78,13 @@ pub struct SameDLogProof {
t: Scalar,
}
impl SameDLogProof {
pub fn verify(&self,pp: &SameDLogProofPublic) -> bool{
pub fn verify(&self, pp: &SameDLogProofPublic) -> bool {
let c = utils::hash_gt_to_scalar(&[&pp.g, &pp.h, &pp.y1, &pp.y2]);
self.a == (pp.g * self.t) + (pp.y1 * c) && self.b == (pp.h * self.t) + (pp.y2 * c)
}
}
#[test]
fn test_proof_correct() {
let x = utils::random_scalar();
@ -83,7 +105,6 @@ fn test_proof_incorrect() {
assert!(!proof.verify(&pp));
}
#[test]
fn test_proof_serialize() {
let x = utils::random_scalar();
@ -94,4 +115,355 @@ fn test_proof_serialize() {
let serialized = serde_json::to_string(&proof).unwrap();
let proof2: SameDLogProof = serde_json::from_str(&serialized).unwrap();
assert_eq!(proof, proof2);
}
}
use arkworks_mimc::params::mimc_7_91_bls12_381::{
MIMC_7_91_BLS12_381_PARAMS, MIMC_7_91_BLS12_381_ROUND_KEYS,
};
use arkworks_mimc::params::round_keys_contants_to_vec;
use arkworks_mimc::MiMC;
//mimc-7-91-bls12-381
use ark_bls12_381::Fr;
use ark_bls12_381::Fq;
use ark_ff::Field;
use ark_ff::PrimeField;
use ark_ff::Zero;
use bls12_381::*;
#[test]
fn test_mimc_hash() {
let mimc = MiMC::<Fr, MIMC_7_91_BLS12_381_PARAMS>::new(
1,
Fr::zero(),
round_keys_contants_to_vec(&MIMC_7_91_BLS12_381_ROUND_KEYS),
);
println!(
"mimc hash: {:?}",
mimc.permute_non_feistel(vec![Fr::zero()])
);
}
// nizk for p2,pw,n,r prove that p2 = r * mimc(pw,n) which is g2/str to g2 where p2 is public
use ark_std;
use arkworks_mimc::{
constraints::{MiMCFeistelCRHGadget},
MiMCFeistelCRH
};
use ark_crypto_primitives::{
crh::{TwoToOneCRH, TwoToOneCRHGadget},
CRH as CRHTrait,
};
use ark_ff::to_bytes;
use ark_r1cs_std::{
fields::fp::FpVar,
prelude::{AllocVar},
R1CSVar, ToBytesGadget,
};
use ark_serialize::{CanonicalSerialize, CanonicalDeserialize};
use ark_std::io::{Read, Write};
use sha2::Digest;
use std::ops::MulAssign;
use ark_serialize::SerializationError;
//TODO Type conversion
//TODO add to server
//TODO add to client
//TODO 32 bytes?
pub fn setup_hash_proof() -> (ProvingKey<Bls12_381>, VerifyingKey<Bls12_381>, PreparedVerifyingKey<Bls12_381>) {
let a = Fr::from(20); // No idea why this is needed // TODO remove once fixed
let test: HashProof = HashProof {
pw_point: Some(a),
nonce_point: Some(a),
random_r: Some(a),
};
let mut rng = OsRng::default();
let (pk, vk) = Groth16::<Bls12_381>::setup(test.clone(), &mut rng).unwrap();
let pvk = prepare_verifying_key::<Bls12_381>(&vk);
(pk, vk, pvk)
}
pub fn generate_hash_proof(username: &String, password: &String, nonce: &Scalar,random: &Scalar,pk: &ProvingKey<Bls12_381>)-> (Scalar,Vec<u8>){
// hash the password and nonce to Fr
let n_fr = Fr::from_le_bytes_mod_order(&nonce.to_bytes());
//use sha256
let mut hasher = sha2::Sha256::new();
hasher.update(username.as_bytes());
hasher.update(password.as_bytes());
let hash = hasher.finalize();
let hash_fr = Fr::from_le_bytes_mod_order(&hash);
// hash the two Fr to Fr
let random_fr = Fr::from_le_bytes_mod_order(&random.to_bytes());
let mimc = MiMC::<Fr, MIMC_7_91_BLS12_381_PARAMS>::new(
1,
Fr::zero(),
round_keys_contants_to_vec(&MIMC_7_91_BLS12_381_ROUND_KEYS),
);
let hashed = <MiMCFeistelCRH<Fr, _> as TwoToOneCRH>::evaluate(
&mimc,
&to_bytes!(hash_fr).unwrap(),
&to_bytes!(n_fr).unwrap(),
).unwrap();
let result_fr = random_fr * hashed;
let mut result_vec = Vec::new();
result_fr.serialize(&mut result_vec).unwrap();
// convert to &[u8; 32]
let result_arr = result_vec.as_slice().try_into().unwrap();
let result_scalar = Scalar::from_bytes(result_arr).unwrap();
let proof = HashProof {
pw_point: Some(hash_fr),
nonce_point: Some(n_fr),
random_r: Some(random_fr),
};
let proof = Groth16::<Bls12_381>::prove(
&pk,
proof,
&mut ark_std::test_rng(),
).unwrap();
let mut proof_serialized = Vec::<u8>::new();
proof.serialize(&mut proof_serialized).unwrap();
(result_scalar,proof_serialized)
}
pub fn validate_hash_proof(scalar: &Scalar, proof: &Vec<u8>, vk: &PreparedVerifyingKey<Bls12_381>) -> bool {
match Proof::<Bls12_381>::deserialize(&proof[..]) {
Ok(proof) => {
let g2_fr = Fr::from_le_bytes_mod_order(&scalar.to_bytes());
match Groth16::<Bls12_381>::verify_with_processed_vk(&vk, &[g2_fr], &proof) {
Ok(result) => result,
Err(_) => false,
}
}
Err(_) => false,
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash,CanonicalSerialize, CanonicalDeserialize)]
pub struct HashProof {
pub pw_point: Option<Fr>,
pub nonce_point: Option<Fr>,
pub random_r: Option<Fr>,
}
impl ConstraintSynthesizer<Fr> for HashProof {
fn generate_constraints(self, cs: ConstraintSystemRef<Fr>) -> Result<(), SynthesisError> {
let mimc = MiMC::<Fr, MIMC_7_91_BLS12_381_PARAMS>::new(
1,
Fr::zero(),
round_keys_contants_to_vec(&MIMC_7_91_BLS12_381_ROUND_KEYS),
);
let x_l = self.pw_point.ok_or(SynthesisError::AssignmentMissing)?;
let x_r = self.nonce_point.ok_or(SynthesisError::AssignmentMissing)?;
let c_r = self.random_r.ok_or(SynthesisError::AssignmentMissing)?;
let x_l_var = FpVar::new_witness(cs.clone(), || Ok(x_l) )?;
let x_r_var = FpVar::new_witness(cs.clone(), || Ok(x_r) )?;
let c_r_var = FpVar::new_witness(cs.clone(), || Ok(c_r) )?;
let k_var = FpVar::new_constant(cs.clone(), &mimc.k)?;
let round_keys = Vec::<FpVar<_>>::new_constant(cs.clone(), mimc.round_keys)?;
let mimc_var = MiMCVar::<_, _>::new(1, k_var, round_keys);
let hashed_var =
<MiMCFeistelCRHGadget<_, MIMC_7_91_BLS12_381_PARAMS> as TwoToOneCRHGadget<
MiMCFeistelCRH<_, _>,
_,
>>::evaluate(&mimc_var, &x_l_var.to_bytes()?, &x_r_var.to_bytes()?)
.unwrap();
// mult c and hashed_var
let result = FpVar::new_input(cs.clone(), || {
let mut res = c_r_var.value()?;
res.mul_assign(&hashed_var.value()?);
Ok(res)
})?;
Ok(())
}
}
#[test]
fn test_type_conversion() {
let usename = String::from("username");
let password = String::from("password");
let nonce = utils::random_scalar();
let random = utils::random_scalar();
let (pk, vk, pvk) = setup_hash_proof();
let (sclar1, proof) = generate_hash_proof(&usename, &password, &nonce, &random, &pk);
let res = validate_hash_proof(&sclar1, &proof, &pvk);
assert!(res);
// change g2 and test for inequality
let mut scalar2 = sclar1;
scalar2 *= utils::random_scalar();
let res = validate_hash_proof(&scalar2, &proof, &pvk);
assert!(!res);
// change proof and test for inequality
let mut proof2 = proof;
proof2[0] = 0;
let res = validate_hash_proof(&sclar1, &proof2, &pvk);
assert!(!res);
}
#[test]
fn test_groth16() {
let mut rng = &mut ark_std::test_rng();
let mimc = MiMC::<Fr, MIMC_7_91_BLS12_381_PARAMS>::new(
1,
Fr::zero(),
round_keys_contants_to_vec(&MIMC_7_91_BLS12_381_ROUND_KEYS),
);
let a = Fr::from(20);
let b = Fr::from(200);
let c = Fr::from(10);
let d = c * <MiMCFeistelCRH<Fr, _> as TwoToOneCRH>::evaluate(
&mimc,
&to_bytes!(a).unwrap(),
&to_bytes!(b).unwrap(),
)
.unwrap();
// instantce g2
let mut bytes = Vec::<u8>::new();
d.serialize(&mut bytes).unwrap();
let mut buf = [0u8; 32];
(&mut buf[0..32]).copy_from_slice(&bytes[..]);
let scalar = Scalar::from_bytes(&buf).unwrap();
let point = G2Affine::generator() * scalar;
println!("point: {:?}", point);
let test: HashProof = HashProof {
pw_point: Some(a),
nonce_point: Some(b),
random_r: Some(c), };
let (pk, vk) = Groth16::<Bls12_381>::setup(test.clone(), &mut rng).unwrap();
let pvk = prepare_verifying_key::<Bls12_381>(&vk);
let proof = Groth16::<Bls12_381>::prove(
&pk,
HashProof {
pw_point: Some(a),
nonce_point: Some(b),
random_r: Some(c),
},
&mut rng,
)
.unwrap();
let start = Instant::now();
for _i in 0..100{
let proof = Groth16::<Bls12_381>::prove(
&pk,
HashProof {
pw_point: Some(a),
nonce_point: Some(b),
random_r: Some(c),
},
&mut rng,
)
.unwrap();
}
println!("{:.2?} Groth16::<Bls12_381>::prove(", start.elapsed()/100);
let res = Groth16::<Bls12_381>::verify_with_processed_vk(&pvk, &[d], &proof);
// let start = Instant::now();
// for _i in 0..100{
// let res = Groth16::<Bls12_381>::verify_with_processed_vk(&pvk, &[a,b,Fr::from(1)], &proof);
// }
println!("{:.2?} verify_with_processed_vk", start.elapsed()/100);
println!("res: {:?}", res.unwrap());
//serialization test
let mut compressed_proof = Vec::new();
proof.serialize(&mut compressed_proof).unwrap();
let proof2 = Proof::<Bls12_381>::deserialize(&compressed_proof[..]).unwrap();
assert_eq!(proof, proof2);
let mut compressed_pvk = Vec::new();
vk.serialize(&mut compressed_pvk).unwrap();
let vk2 = VerifyingKey::<Bls12_381>::deserialize(&compressed_pvk[..]).unwrap();
assert_eq!(vk, vk2);
let pk2 = prepare_verifying_key(&vk2);
assert_eq!(pvk, pk2);
}
#[test]
fn test_constraint() -> Result<(), ark_relations::r1cs::SynthesisError> {
let rng = &mut ark_std::test_rng();
let cs = ConstraintSystem::<Fr>::new_ref();
let mimc = MiMC::<Fr, MIMC_7_91_BLS12_381_PARAMS>::new(
1,
Fr::zero(),
round_keys_contants_to_vec(&MIMC_7_91_BLS12_381_ROUND_KEYS),
);
let x_l = Fr::from(20);
let x_r = Fr::from(200);
let hashed = <MiMCFeistelCRH<Fr, _> as TwoToOneCRH>::evaluate(
&mimc,
&to_bytes!(x_l).unwrap(),
&to_bytes!(x_r).unwrap(),
)
.unwrap();
let x_l_var = FpVar::new_witness(cs.clone(), || Ok(x_l))?;
let x_r_var = FpVar::new_witness(cs.clone(), || Ok(x_r))?;
let k_var = FpVar::new_input(cs.clone(), || Ok(mimc.k))?;
let round_keys = Vec::<FpVar<Fr>>::new_constant(cs.clone(), mimc.round_keys)?;
let mimc_var = MiMCVar::<_, _>::new(1, k_var, round_keys);
let hashed_var = <MiMCFeistelCRHGadget<_, MIMC_7_91_BLS12_381_PARAMS> as TwoToOneCRHGadget<
MiMCFeistelCRH<_, _>,
_,
>>::evaluate(&mimc_var, &x_l_var.to_bytes()?, &x_r_var.to_bytes()?)
.unwrap();
assert!(FpVar::constant(hashed).is_eq(&hashed_var)?.value()?);
let additional_input = FpVar::new_input(cs.clone(), || Ok(Fr::from(10)))?;
// make input additional_input * hashed
let hashed_var2 = hashed_var.clone() * additional_input;
println!("hashed: {:?}", hashed_var2.value()?);
cs.is_satisfied()?;
println!("constraints: {}", cs.clone().num_constraints());
println!("inputs: {}", cs.clone().num_instance_variables());
println!("aux: {}", cs.clone().num_witness_variables());
// try building a circurit for the nizk
Ok(())
}