use crate::{
extends::{AffineExtend, ScalarExtend},
hash::{hash_points, hash_points_prefix, hash_to_curve, hash_to_curve_prefix},
helper::*,
};
use libsecp256k1::{
curve::{Affine, ECMultContext, ECMultGenContext, Field, Jacobian, Scalar, AFFINE_G},
util::{FULL_PUBLIC_KEY_SIZE, SECRET_KEY_SIZE},
PublicKey, SecretKey, ECMULT_CONTEXT, ECMULT_GEN_CONTEXT,
};
use rand::thread_rng;
pub trait Zeroable {
fn zeroize(&mut self);
fn is_zero(&self) -> bool;
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct KeyPair {
pub public_key: PublicKey,
pub secret_key: SecretKey,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct RawKeyPair {
pub public_key: [u8; FULL_PUBLIC_KEY_SIZE],
pub secret_key: [u8; SECRET_KEY_SIZE],
}
impl KeyPair {
pub fn new() -> Self {
let mut rng = thread_rng();
let secret_key = SecretKey::random(&mut rng);
let public_key = PublicKey::from_secret_key(&secret_key);
KeyPair {
public_key,
secret_key,
}
}
}
impl Zeroable for RawKeyPair {
fn zeroize(&mut self) {
for i in 0..self.public_key.len() {
self.public_key[i] ^= self.public_key[i];
}
for i in 0..self.secret_key.len() {
self.secret_key[i] ^= self.secret_key[i];
}
}
fn is_zero(&self) -> bool {
for i in 0..self.public_key.len() {
if self.public_key[i] != 0 {
return false;
}
}
for i in 0..self.secret_key.len() {
if self.secret_key[i] != 0 {
return false;
}
}
true
}
}
impl From<SecretKey> for KeyPair {
fn from(value: SecretKey) -> Self {
KeyPair {
public_key: PublicKey::from_secret_key(&value),
secret_key: value,
}
}
}
impl From<KeyPair> for RawKeyPair {
fn from(value: KeyPair) -> Self {
RawKeyPair {
public_key: value.public_key.serialize(),
secret_key: value.secret_key.serialize(),
}
}
}
impl From<&[u8; SECRET_KEY_SIZE]> for RawKeyPair {
fn from(value: &[u8; SECRET_KEY_SIZE]) -> Self {
let secret_instance = SecretKey::parse(value).expect("Can not parse secret key");
let public_key = PublicKey::from_secret_key(&secret_instance).serialize();
RawKeyPair {
public_key,
secret_key: value.clone(),
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct ECVRFProof {
pub gamma: Affine,
pub c: Scalar,
pub s: Scalar,
pub y: Scalar,
pub pk: PublicKey,
}
#[derive(Clone, Copy, Debug)]
pub struct ECVRFContractProof {
pub pk: PublicKey,
pub gamma: Affine,
pub c: Scalar,
pub s: Scalar,
pub y: Scalar,
pub alpha: Scalar,
pub witness_address: Scalar,
pub witness_gamma: Affine,
pub witness_hash: Affine,
pub inverse_z: Field,
}
pub struct ECVRF<'a> {
secret_key: SecretKey,
public_key: PublicKey,
ctx_mul: &'a ECMultContext,
ctx_gen: &'a ECMultGenContext,
}
impl ECVRF<'_> {
pub fn new(secret_key: SecretKey) -> Self {
ECVRF {
secret_key: secret_key,
public_key: PublicKey::from_secret_key(&secret_key),
ctx_gen: &ECMULT_GEN_CONTEXT,
ctx_mul: &ECMULT_CONTEXT,
}
}
pub fn prove_contract(&self, alpha: &Scalar) -> ECVRFContractProof {
let mut pub_affine: Affine = self.public_key.into();
let mut secret_key: Scalar = self.secret_key.into();
pub_affine.x.normalize();
pub_affine.y.normalize();
let h = hash_to_curve_prefix(alpha, &pub_affine);
let gamma = ecmult(self.ctx_mul, &h, &secret_key);
let mut k = Scalar::randomize();
while k.gte(&GROUP_ORDER) || k.is_zero() {
k = Scalar::randomize();
}
let kg = ecmult_gen(self.ctx_gen, &k);
let u_witness = calculate_witness_address(&kg);
let kh = ecmult(self.ctx_mul, &h, &k);
let c = hash_points_prefix(&h, &pub_affine, &gamma, &u_witness, &kh);
let mut neg_c = c.clone();
neg_c.cond_neg_assign(1.into());
let s = k + neg_c * secret_key;
secret_key.clear();
let witness_gamma = ecmult(self.ctx_mul, &gamma, &c);
let witness_hash = ecmult(self.ctx_mul, &h, &s);
let v = projective_ec_add(&witness_gamma, &witness_hash);
let mut inverse_z = v.z.inv();
inverse_z.normalize();
ECVRFContractProof {
pk: self.public_key,
gamma,
c,
s,
y: Scalar::from_bytes(&gamma.keccak256()),
alpha: *alpha,
witness_address: Scalar::from_bytes(&u_witness),
witness_gamma,
witness_hash,
inverse_z,
}
}
pub fn prove(&self, alpha: &Scalar) -> ECVRFProof {
let mut pub_affine: Affine = self.public_key.into();
let mut secret_key: Scalar = self.secret_key.into();
pub_affine.x.normalize();
pub_affine.y.normalize();
let h = hash_to_curve(alpha, Some(&pub_affine));
let gamma = ecmult(self.ctx_mul, &h, &secret_key);
let mut k = Scalar::randomize();
while k.gte(&GROUP_ORDER) || k.is_zero() {
k = Scalar::randomize();
}
let kg = ecmult_gen(self.ctx_gen, &k);
let kh = ecmult(self.ctx_mul, &h, &k);
let c = hash_points(&AFFINE_G, &h, &pub_affine, &gamma, &kg, &kh);
let mut neg_c = c.clone();
neg_c.cond_neg_assign(1.into());
let s = k + neg_c * secret_key;
secret_key.clear();
let y = Scalar::from_bytes(&gamma.keccak256());
ECVRFProof {
gamma,
c,
s,
y,
pk: self.public_key,
}
}
pub fn verify(&self, alpha: &Scalar, vrf_proof: &ECVRFProof) -> bool {
let mut pub_affine: Affine = self.public_key.into();
pub_affine.x.normalize();
pub_affine.y.normalize();
assert!(pub_affine.is_valid_var());
assert!(vrf_proof.gamma.is_valid_var());
let h = hash_to_curve(alpha, Some(&pub_affine));
let mut jh = Jacobian::default();
jh.set_ge(&h);
let mut u = Jacobian::default();
let pub_jacobian = Jacobian::from_ge(&pub_affine);
self.ctx_mul
.ecmult(&mut u, &pub_jacobian, &vrf_proof.c, &vrf_proof.s);
let witness_gamma = ecmult(self.ctx_mul, &vrf_proof.gamma, &vrf_proof.c);
let witness_hash = ecmult(self.ctx_mul, &h, &vrf_proof.s);
let v = Jacobian::from_ge(&witness_gamma).add_ge(&witness_hash);
let computed_c = hash_points(
&AFFINE_G,
&h,
&pub_affine,
&vrf_proof.gamma,
&jacobian_to_affine(&u),
&jacobian_to_affine(&v),
);
let computed_y = Scalar::from_bytes(&vrf_proof.gamma.keccak256());
computed_c.eq(&vrf_proof.c) && computed_y.eq(&vrf_proof.y)
}
}
#[cfg(test)]
mod tests {
use crate::{extends::ScalarExtend, ECVRF};
use libsecp256k1::{curve::Scalar, SecretKey};
use rand::thread_rng;
#[test]
fn we_should_able_to_prove_and_verify() {
let mut r = thread_rng();
let secret_key = SecretKey::random(&mut r);
let ecvrf = ECVRF::new(secret_key);
let alpha = Scalar::randomize();
let r1 = ecvrf.prove(&alpha);
let r2 = ecvrf.verify(&alpha, &r1);
assert!(r2);
}
}