arnaucube
arnaucube/NovaPublic Self-hosted repository
Support Pasta curves. (#4)

* Support pasta curves directly.

* Upgrade rand.

* Simplify.

* Don't deny missing docs.

Co-authored-by: porcuquine <porcuquine@users.noreply.github.com>
porcuquine 1746729+porcuquine@users.noreply.github.com
Mon, 27 Sep 2021 18:23:40 -0700
commit

de5b8d6598f2ea9f9500613e204018652a319978

parent

bf08877544e0e414804162f02a7df6269c045594

3 files changed, 93 insertions(+), 85 deletions(-)

jump to
M Cargo.toml → 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"]}+pasta_curves = "0.2.1"
M src/lib.rs → src/lib.rs

@@ -6,6 +6,7 @@ #![deny(missing_docs)]

mod commitments; pub mod errors; +pub mod pasta; pub mod r1cs; pub mod traits;

@@ -125,88 +126,11 @@

#[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; + use crate::traits::PrimeField; + use rand::rngs::OsRng; - fn vartime_multiscalar_mul<I, J>(scalars: I, points: J) -> Self - where - I: IntoIterator, - I::Item: Borrow<Self::Scalar>, - J: IntoIterator, - J::Item: Borrow<Self>, - Self: Clone, - { - Self::multiscalar_mul(scalars, points) - } - - fn compress(&self) -> Self::CompressedGroupElement { - self.compress() - } - - fn from_uniform_bytes(bytes: &[u8]) -> Option<Self> { - 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<Self> { - 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; - - fn decompress(&self) -> Option<Self::GroupElement> { - 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() {
A 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 = <pallas::Point as GroupEncoding>::Repr; + + fn vartime_multiscalar_mul<I, J>(scalars: I, points: J) -> Self + where + I: IntoIterator, + I::Item: Borrow<Self::Scalar>, + J: IntoIterator, + J::Item: Borrow<Self>, + 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<Self> { + 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<Self> { + 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 <pallas::Point as GroupEncoding>::Repr { + type GroupElement = pallas::Point; + fn decompress(&self) -> Option<<Self as CompressedGroup>::GroupElement> { + Some(Ep::from_bytes(&self).unwrap()) + } + fn as_bytes(&self) -> &[u8] { + self + } +}