From de5b8d6598f2ea9f9500613e204018652a319978 Mon Sep 17 00:00:00 2001 From: porcuquine <1746729+porcuquine@users.noreply.github.com> Date: Mon, 27 Sep 2021 18:23:40 -0700 Subject: [PATCH] Support Pasta curves. (#4) * Support pasta curves directly. * Upgrade rand. * Simplify. * Don't deny missing docs. Co-authored-by: porcuquine --- Cargo.toml | 6 ++-- src/lib.rs | 86 +++------------------------------------------------- src/pasta.rs | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 85 deletions(-) create mode 100644 src/pasta.rs diff --git a/Cargo.toml b/Cargo.toml index b1bbcfb..656d2e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,13 +12,11 @@ keywords = ["zkSNARKs", "cryptography", "proofs"] [dependencies] merlin = "2.0.0" -rand = "0.7.3" +rand = "0.8.4" digest = "0.8.1" sha3 = "0.8.2" rayon = "1.3.0" rand_core = { version = "0.5", default-features = false } itertools = "0.9.0" subtle = "2.4" - -[dev-dependencies] -curve25519-dalek = {version = "3.0.0", features = ["simd_backend"]} \ No newline at end of file +pasta_curves = "0.2.1" diff --git a/src/lib.rs b/src/lib.rs index 63d77a2..fea21ac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ mod commitments; pub mod errors; +pub mod pasta; pub mod r1cs; pub mod traits; @@ -125,88 +126,11 @@ impl FinalSNARK { #[cfg(test)] mod tests { use super::*; - use crate::traits::{CompressedGroup, Group, PrimeField}; - use core::borrow::Borrow; - use curve25519_dalek::traits::MultiscalarMul; - use rand::{rngs::OsRng, CryptoRng, RngCore}; - - type S = curve25519_dalek::scalar::Scalar; - type G = curve25519_dalek::ristretto::RistrettoPoint; - type C = curve25519_dalek::ristretto::CompressedRistretto; - - impl Group for G { - type Scalar = S; - type CompressedGroupElement = C; - - fn vartime_multiscalar_mul(scalars: I, points: J) -> Self - where - I: IntoIterator, - I::Item: Borrow, - J: IntoIterator, - J::Item: Borrow, - Self: Clone, - { - Self::multiscalar_mul(scalars, points) - } - - fn compress(&self) -> Self::CompressedGroupElement { - self.compress() - } - - fn from_uniform_bytes(bytes: &[u8]) -> Option { - if bytes.len() != 64 { - None - } else { - let mut arr = [0; 64]; - arr.copy_from_slice(&bytes[0..64]); - Some(Self::from_uniform_bytes(&arr)) - } - } - } - - impl PrimeField for S { - fn zero() -> Self { - S::zero() - } - - fn one() -> Self { - S::one() - } - - fn from_bytes_mod_order_wide(bytes: &[u8]) -> Option { - if bytes.len() != 64 { - None - } else { - let mut arr = [0; 64]; - arr.copy_from_slice(&bytes[0..64]); - Some(Self::from_bytes_mod_order_wide(&arr)) - } - } - - fn random(rng: &mut (impl RngCore + CryptoRng)) -> Self { - S::random(rng) - } - } - - impl CompressedGroup for C { - type GroupElement = G; + use crate::traits::PrimeField; + use rand::rngs::OsRng; - fn decompress(&self) -> Option { - self.decompress() - } - - fn as_bytes(&self) -> &[u8] { - self.as_bytes() - } - } - - impl ChallengeTrait for S { - fn challenge(label: &'static [u8], transcript: &mut Transcript) -> Self { - let mut buf = [0u8; 64]; - transcript.challenge_bytes(label, &mut buf); - S::from_bytes_mod_order_wide(&buf) - } - } + type S = pasta_curves::pallas::Scalar; + type G = pasta_curves::pallas::Point; #[test] fn test_tiny_r1cs() { diff --git a/src/pasta.rs b/src/pasta.rs new file mode 100644 index 0000000..b3637ff --- /dev/null +++ b/src/pasta.rs @@ -0,0 +1,86 @@ +//! This module implements the Nova traits for pallas::Point and pallas::Scalar. +use crate::traits::{ChallengeTrait, CompressedGroup, Group, PrimeField}; +use merlin::Transcript; +use pasta_curves::arithmetic::{CurveExt, FieldExt, Group as Grp}; +use pasta_curves::group::GroupEncoding; +use pasta_curves::{self, pallas, Ep, Fq}; +use rand::{CryptoRng, RngCore}; +use std::borrow::Borrow; +use std::ops::Mul; + +impl Group for pallas::Point { + type Scalar = pallas::Scalar; + type CompressedGroupElement = ::Repr; + + fn vartime_multiscalar_mul(scalars: I, points: J) -> Self + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + Self: Clone, + { + // Unoptimized. + scalars + .into_iter() + .zip(points) + .map(|(scalar, point)| (*point.borrow()).mul(*scalar.borrow())) + .fold(Ep::group_zero(), |acc, x| acc + x) + } + + fn compress(&self) -> Self::CompressedGroupElement { + self.to_bytes() + } + + fn from_uniform_bytes(bytes: &[u8]) -> Option { + if bytes.len() != 64 { + None + } else { + let mut arr = [0; 32]; + arr.copy_from_slice(&bytes[0..32]); + + let hash = Ep::hash_to_curve("from_uniform_bytes"); + Some(hash(&arr)) + } + } +} + +impl PrimeField for pallas::Scalar { + fn zero() -> Self { + Fq::zero() + } + fn one() -> Self { + Fq::one() + } + fn from_bytes_mod_order_wide(bytes: &[u8]) -> Option { + if bytes.len() != 64 { + None + } else { + let mut arr = [0; 64]; + arr.copy_from_slice(&bytes[0..64]); + Some(Fq::from_bytes_wide(&arr)) + } + } + + fn random(_rng: &mut (impl RngCore + CryptoRng)) -> Self { + Fq::rand() + } +} + +impl ChallengeTrait for pallas::Scalar { + fn challenge(label: &'static [u8], transcript: &mut Transcript) -> Self { + let mut buf = [0u8; 64]; + transcript.challenge_bytes(label, &mut buf); + pallas::Scalar::from_bytes_mod_order_wide(&buf).unwrap() + } +} + +impl CompressedGroup for ::Repr { + type GroupElement = pallas::Point; + fn decompress(&self) -> Option<::GroupElement> { + Some(Ep::from_bytes(&self).unwrap()) + } + fn as_bytes(&self) -> &[u8] { + self + } +}