Przeglądaj źródła

research/ecvrf: Basic implementation

parazyd 3 lat temu
rodzic
commit
0a13dcc648

+ 3 - 0
script/research/ecvrf/.gitignore

@@ -0,0 +1,3 @@
+Cargo.lock
+target/
+*.bin

+ 19 - 0
script/research/ecvrf/Cargo.toml

@@ -0,0 +1,19 @@
+[package]
+name = "ecvrf"
+version = "0.4.1"
+authors = ["Dyne.org foundation <foundation@dyne.org>"]
+license = "AGPL-3.0-only"
+edition = "2021"
+
+[workspace]
+
+[dependencies]
+blake3 = "1.3.3"
+darkfi-sdk = {path = "../../../src/sdk"}
+darkfi = {path = "../../../", features = ["zk"]}
+lazy_static = "1.4.0"
+rand = "0.8.5"
+halo2_gadgets = "0.3.0"
+
+[patch.crates-io]
+halo2_proofs = {git="https://github.com/parazyd/halo2", branch="v3"}

+ 116 - 0
script/research/ecvrf/src/main.rs

@@ -0,0 +1,116 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2023 Dyne.org foundation
+ * Copyright (C) 2021 Silur <https://github.com/Silur/ECVRF/>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+use darkfi_sdk::{
+    crypto::{
+        constants::NullifierK,
+        pasta_prelude::{CurveExt, Field},
+        util::mod_r_p,
+        Keypair, PublicKey, SecretKey,
+    },
+    pasta::{
+        group::{ff::FromUniformBytes, GroupEncoding},
+        pallas,
+    },
+};
+use halo2_gadgets::ecc::chip::FixedPoint;
+use rand::rngs::OsRng;
+
+struct VrfProof {
+    gamma: pallas::Point,
+    c: [u8; 32],
+    s: pallas::Scalar,
+}
+
+fn keygen() -> Keypair {
+    Keypair::random(&mut OsRng)
+}
+
+/// The output of a VRF function is the VRF hash and the proof to verify
+/// we generated this hash with the supplied key.
+fn prove(input: &[u8], secret_key: &SecretKey) -> ([u8; 32], VrfProof) {
+    let h = pallas::Point::hash_to_curve("ecvrf")(input);
+    let gamma = h * mod_r_p(secret_key.inner());
+    let k = pallas::Scalar::random(&mut OsRng);
+
+    // TODO: Valid to use this as basepoint?
+    let g = NullifierK.generator();
+
+    let mut hasher = blake3::Hasher::new();
+    // TODO: Basepoint?
+    hasher.update(&g.to_bytes());
+    hasher.update(&h.to_bytes());
+    hasher.update(&(g * mod_r_p(secret_key.inner())).to_bytes());
+    hasher.update(&(h * mod_r_p(secret_key.inner())).to_bytes());
+    hasher.update(&(g * k).to_bytes());
+    hasher.update(&(h * k).to_bytes());
+
+    let mut c = [0_u8; 64];
+    let binding = hasher.finalize();
+    let hres = binding.as_bytes();
+    for i in 0..hres.len() {
+        c[i] = hres[i];
+    }
+
+    let c_scalar = pallas::Scalar::from_uniform_bytes(&c);
+    let s = k - c_scalar * mod_r_p(secret_key.inner());
+    let beta = blake3::hash(&gamma.to_bytes());
+
+    (beta.into(), VrfProof { gamma, c: c[..32].try_into().unwrap(), s })
+}
+
+fn verify(input: &[u8], pubkey: &PublicKey, output: &[u8; 32], proof: &VrfProof) -> bool {
+    let mut c = [0_u8; 64];
+    for i in 0..proof.c.len() {
+        c[i] = proof.c[i];
+    }
+
+    // TODO: Valid to use this as basepoint?
+    let g = NullifierK.generator();
+
+    let c_scalar = pallas::Scalar::from_uniform_bytes(&c);
+    let u = pubkey.inner() * c_scalar + g * proof.s;
+    let h = pallas::Point::hash_to_curve("ecvrf")(input);
+    let v = proof.gamma * c_scalar + h * proof.s;
+
+    let mut hasher = blake3::Hasher::new();
+    // TODO: Basepoint?
+    hasher.update(&g.to_bytes());
+    hasher.update(&h.to_bytes());
+    hasher.update(&pubkey.inner().to_bytes());
+    hasher.update(&proof.gamma.to_bytes());
+    hasher.update(&u.to_bytes());
+    hasher.update(&v.to_bytes());
+
+    let mut local_c = [0_u8; 32];
+    let binding = hasher.finalize();
+    let hres = binding.as_bytes();
+    for i in 0..hres.len() {
+        local_c[i] = hres[i];
+    }
+
+    blake3::hash(&proof.gamma.to_bytes()).as_bytes() == output && local_c == proof.c
+}
+
+fn main() {
+    let keypair = keygen();
+    let input = vec![0xde, 0xad, 0xbe, 0xef];
+    let (output, proof) = prove(&input, &keypair.secret);
+    assert!(verify(&input, &keypair.public, &output, &proof));
+}