g1 handling

This commit is contained in:
NikVolf 2019-03-12 18:45:49 +03:00
parent 134500ffdc
commit 5d5b76bdcc
3 changed files with 93 additions and 8 deletions

6
Cargo.lock generated
View File

@ -132,7 +132,7 @@ dependencies = [
"bellman 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc.git?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)",
"blake2b_simd 0.4.1 (git+https://github.com/oconnor663/blake2b_simd.git)",
"bn 0.4.4 (git+https://github.com/paritytech/bn)",
"bn 0.4.4 (git+https://github.com/paritytech/bn?branch=upgrade)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pairing 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)",
"primitives 0.1.0",
@ -174,7 +174,7 @@ dependencies = [
[[package]]
name = "bn"
version = "0.4.4"
source = "git+https://github.com/paritytech/bn#2a71dbde5ca93451c8da2135767896a64483759e"
source = "git+https://github.com/paritytech/bn?branch=upgrade#e9f64f518d0ae64cb4f9a8c7c544e3ff0ef82584"
dependencies = [
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"crunchy 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2010,7 +2010,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc.git?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)" = "<none>"
"checksum blake2b_simd 0.4.1 (git+https://github.com/oconnor663/blake2b_simd.git)" = "<none>"
"checksum bn 0.4.4 (git+https://github.com/paritytech/bn)" = "<none>"
"checksum bn 0.4.4 (git+https://github.com/paritytech/bn?branch=upgrade)" = "<none>"
"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
"checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa"
"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749"

View File

@ -12,7 +12,7 @@ sapling-crypto = { git = "https://github.com/zcash-hackworks/sapling-crypto.git"
serde_json = "1.0"
siphasher = "0.1.1"
primitives = { path = "../primitives" }
bn = { git = "https://github.com/paritytech/bn" }
bn = { git = "https://github.com/paritytech/bn", branch = "upgrade" }
serde = "1.0"
serde_derive = "1.0"
rustc-hex = "2"

View File

@ -1,5 +1,6 @@
pub use bn::{Fr, G1, G2, Group};
pub use bn::{Fr, Fq, G1, G2, Group, arith::U256, AffineG1};
use bn::pairing;
use std::ops::Neg;
#[derive(Clone)]
pub struct VerifyingKey {
@ -19,6 +20,13 @@ impl ::std::fmt::Debug for VerifyingKey {
}
}
#[derive(Debug)]
pub enum Error {
InvalidFieldElement,
InvalidCurvePoint,
InvalidRawInput,
}
#[derive(Clone)]
pub struct Proof {
pub a: G1,
@ -31,6 +39,57 @@ pub struct Proof {
pub h: G1,
}
lazy_static! {
pub static ref FQ: U256 = U256::from([
0x3c208c16d87cfd47,
0x97816a916871ca8d,
0xb85045b68181585d,
0x30644e72e131a029
]);
pub static ref G1_B: Fq = Fq::from_u256(3.into()).expect("3 is a valid field element and static; qed");
pub static ref FQ_MINUS3_DIV4: Fq =
Fq::from_u256(3.into()).expect("3 is a valid field element and static; qed").neg() *
Fq::from_u256(4.into()).expect("4 is a valid field element and static; qed").inverse()
.expect("4 has inverse in Fq and is static; qed");
}
// Shankss algorithm for q ≡ 3 (mod 4)
// (FQ mod 4 = 3)
fn fq_sqrt(a: Fq) -> Option<Fq> {
let a1 = a.pow(*FQ_MINUS3_DIV4);
let a1a = a1 * a;
let a0 = a1 * (a1a);
let mut am1 = *FQ;
am1.sub(&1.into(), &*FQ);
if a0 == Fq::from_u256(am1).unwrap() {
None
} else {
Some(a1a)
}
}
fn g1_from_compressed(data: &[u8]) -> Result<G1, Error> {
if data.len() != 33 { return Err(Error::InvalidRawInput); }
let sign = data[0];
let fq = deseerialize_fq(&data[1..])?;
let x = fq;
let y_squared = (fq * fq * fq) + *G1_B;
let mut y = fq_sqrt(y_squared).ok_or(Error::InvalidFieldElement)?;
if sign == 2 { y = y.neg(); }
AffineG1::new(x, y).map_err(|_| Error::InvalidCurvePoint).map(Into::into)
}
fn deseerialize_fq(data: &[u8]) -> Result<Fq, Error> {
Ok(Fq::from_slice(data).map_err(|_| Error::InvalidRawInput)?)
}
pub fn verify(vk: &VerifyingKey, primary_input: &[Fr], proof: &Proof) -> bool {
let p2 = G2::one();
@ -47,8 +106,34 @@ pub fn verify(vk: &VerifyingKey, primary_input: &[Fr], proof: &Proof) -> bool {
// 3. check same coefficients were used:
pairing(proof.k, vk.gamma) ==
pairing(acc + proof.a + proof.c, vk.gamma_beta_2) * pairing(vk.gamma_beta_1, proof.b) &&
pairing(acc + proof.a + proof.c, vk.gamma_beta_2) * pairing(vk.gamma_beta_1, proof.b) &&
// 4. check QAP divisibility
pairing(acc + proof.a, proof.b) == pairing(proof.h, vk.z) * pairing(proof.c, p2)
}
// 4. check QAP divisibility
pairing(acc + proof.a, proof.b) == pairing(proof.h, vk.z) * pairing(proof.c, p2)
#[cfg(test)]
mod tests {
use super::*;
fn hex(s: &'static str) -> Vec<u8> {
use hex::FromHex;
s.from_hex().unwrap()
}
#[test]
fn sqrt() {
let fq1 = Fq::from_str("5204065062716160319596273903996315000119019512886596366359652578430118331601").unwrap();
let fq2 = Fq::from_str("348579348568").unwrap();
assert_eq!(fq1, fq_sqrt(fq2).expect("348579348568 is quadratic residue"));
}
#[test]
fn g1_deserialize() {
let g1 = g1_from_compressed(&hex("0230644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46")).expect("Invalid g1 decompress result");
assert_eq!(g1.x(), Fq::from_str("21888242871839275222246405745257275088696311157297823662689037894645226208582").unwrap());
assert_eq!(g1.y(), Fq::from_str("3969792565221544645472939191694882283483352126195956956354061729942568608776").unwrap());
assert_eq!(g1.z(), Fq::one());
}
}