Giter Club home page Giter Club logo

openzkp's Introduction

OpenZKP

Crates.io CircleCI Codecov

OpenZKP - pure Rust implementations of Zero-Knowledge Proof systems.

Overview

Project current implements

  • 🐺 the Stark protocol (see its readme for details)

and has

  • 🌞 a simple interface (see the example below),
  • 🗜️ succinct proofs,
  • 🏎️ decent performance, and
  • 🌐 webassembly support.

That being said, it also has a number of limitations, it has

  • no high-level language,
  • no comprehensive security audit,
  • no perfect zero-knowledge,
  • hard-coded field and hash function,

and some others, see features and limitations below for details.

Packages

Package Version Description
utils/
criterion-utils Crates.io Criterion helpers to benchmark over size and number of processors.
error-utils Crates.io Assertion like macros for returning Result::Err.
logging-allocator Crates.io Wrapper around the system allocator that logs large allocations.
mmap-vec Crates.io Substitute for Vec that uses file-backed storage.
macros-lib Crates.io Library of procedural macros implemented using proc_macro2
macros-impl Crates.io Implementation crate for proc_macro_hack
macros-decl Crates.io Procedural macros.
algebra/
u256 Crates.io Implementation of 256-bit unsigned integers.
primefield Crates.io A 251-bit prime field suitable for FFTs.
elliptic-curve Crates.io An elliptic curve over the primefield.
crypto/
elliptic-curve-crypto Crates.io Pedersen commitments and digital signatures.
hash Crates.io Hash primitive used in zkp-stark.
merkle-tree Crates.io Merkle tree based vector commitment.
stark Crates.io STARK protocol implementation

Example

Example from the stark package:

use zkp_stark::{*, primefield::*};

struct FibonacciClaim {
    index: usize,
    value: FieldElement,
}

impl Verifiable for FibonacciClaim {
    fn constraints(&self) -> Constraints {
        use RationalExpression::*;

        // Seed
        let mut seed = self.index.to_be_bytes().to_vec();
        seed.extend_from_slice(&self.value.as_montgomery().to_bytes_be());

        // Constraint repetitions
        let trace_length = self.index.next_power_of_two();
        let g = Constant(FieldElement::root(trace_length).unwrap());
        let on_row = |index| (X - g.pow(index)).inv();
        let every_row = || (X - g.pow(trace_length - 1)) / (X.pow(trace_length) - 1.into());

        let mut c = Constraints::from_expressions((trace_length, 2), seed, vec![
            (Trace(0, 1) - Trace(1, 0)) * every_row(),
            (Trace(1, 1) - Trace(0, 0) - Trace(1, 0)) * every_row(),
            (Trace(0, 0) - 1.into()) * on_row(0),
            (Trace(0, 0) - (&self.value).into()) * on_row(self.index),
        ])
        .unwrap()
    }
}

impl Provable<&FieldElement> for FibonacciClaim {
    fn trace(&self, witness: &FieldElement) -> TraceTable {
        let trace_length = self.index.next_power_of_two();
        let mut trace = TraceTable::new(trace_length, 2);
        trace[(0, 0)] = 1.into();
        trace[(0, 1)] = witness.clone();
        for i in 0..(trace_length - 1) {
            trace[(i + 1, 0)] = trace[(i, 1)].clone();
            trace[(i + 1, 1)] = &trace[(i, 0)] + &trace[(i, 1)];
        }
        trace
    }
}

pub fn main() {
    let claim = FibonacciClaim {
        index: 5000,
        value: FieldElement::from_hex_str("069673d708ad3174714a2c27ffdb56f9b3bfb38c1ea062e070c3ace63e9e26eb"),
    };
    let secret = FieldElement::from(42);
    let proof = claim.prove(&secret).unwrap();
    claim.verify(&proof).unwrap();
}

Features and Limitations

Features

A simple interface. The public interface is simple and is considered semver-stable. Future versions are expected to add functionality without breaking this interface.

Succinct proofs. For a given security parameter, the proof size is close to minimal. Significant improvements here would require innovations in the way constraint systems are designed or in the underlying cryptography.

Decent performance. All steps of the proof are using asymptotically optimal algorithms and all of the major steps are multi-threaded. There are no hard memory requirements. We can expect a good amount of performance improvements by fine-tuning, but we don't expect orders of magnitude improvements.

Webassembly support. The verifier can be used in a WebAssembly environment without the Rust std lib. The prover will work too, but has not been a priority.

Limitations

No high-level language. Constraints are specified using their algebraic expressions. This requires complicated and careful design from the library user and is easy to do wrong, leading to insecure systems. A high level language would help make development simpler and safer and facilitate re-use of components.

No comprehensive security audit. While development is done with the best security practices in mind, it is still very early stage and has not had the amount of expert peer review required for a production grade system.

No perfect zero-knowledge. The current implementation provides succinct proofs but not perfect zero knowledge. While non-trivial, it is theoretically possible to learn something about the secret. Achieving perfect zero-knowledge is possible and can be implemented.

No side-channel resistance. The implementation favours performance over side-channel resistance. While this is common in zero-knowledge proof system, you should be aware that his might leak intermediate computations. Side-channel resistance can be implemented.

Hard-coded field and hash. The current implementation uses a particular prime field and a particular hash function. These are optimized for verification in the Ethereum Virtual Machine. This can be generalized to other primitives optimized for other use cases.

Contributing

See our Contributing guideline and Code of conduct.

See CircleCI documentation on how to run tests locally.

References

Resource overviews on Zero Knowledge Proof protoocols:

Resources on numeric and cryptographic algorithm implementation:

  • Alfred J. Menezes, Paul C. van Oorschot and Scott A. Vanstone (2001). "Handbook of Applied Cryptography". Available online
  • Donald Knuth (1968-). "The art of computer programming". In particular part II: Seminumerical algorithms.

openzkp's People

Contributors

aleph-v avatar z2trillion avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

openzkp's Issues

Convert 19 digits at a time using u64.

On 2019-04-29 @recmo wrote in 1587275 “Added decimal support”:

Convert 19 digits at a time using u64.

            return "0".to_string();
        }
        let mut result = String::new();
        let mut copy = self.clone();
        while copy > Self::ZERO {
            // OPT: Convert 19 digits at a time using u64.
            let digit = (&copy % Self::from(10_u64)).c0;
            result.push_str(&digit.to_string());
            copy /= Self::from(10_u64);
        }
        // Reverse digits

From algebra/u256/src/u256.rs:120

Not supported in cost fn:

On 2019-04-01 @recmo wrote in 07aa473 “Add basecase div”:

Not supported in cost fn:
debug_assert!(q < 0x1_0000_0000_0000_0000_u128);

/// Compute <hi, lo> / d, returning the quotient and the remainder.
#[inline(always)]
pub const fn div_2_1(lo: u64, hi: u64, d: u64) -> (u64, u64) {
    let n = ((hi as u128) << 64) | (lo as u128);
    let q = n / (d as u128);
    // TODO: Not supported in cost fn:
    // debug_assert!(q < 0x1_0000_0000_0000_0000_u128);
    let r = n % (d as u128);
    // We want truncation here
    #[allow(clippy::cast_possible_truncation)]
    (q as u64, r as u64)
}

From algebra/u256/src/utils.rs:44

eliminate .clone()

On 2019-06-21 @recmo wrote in 8b7e45d “Spelling”:

eliminate .clone()

            while remaining_exponent > 0 {
                if remaining_exponent % 2 == 1 {
                    result *= &square;
                }
                remaining_exponent >>= 1;
                // OPT - eliminate .clone()
                square *= square.clone();
            }
            Some(result)
        }
    }

From algebra/u256/src/u256.rs:366

Also accept integer literals

On 2019-08-09 @recmo wrote in 9b150f6 “Add procedural expression macros (#39)”:

Also accept integer literals

    .unwrap_or_else(|err: syn::Error| err.to_compile_error())
}

pub fn u256h(input: TokenStream) -> TokenStream {
    (|| {
        // TODO: Also accept integer literals
        let bytes = parse_hex(input)?;
        let limbs = bytes_to_limbs(bytes.as_slice())?;
        let c0 = Literal::u64_suffixed(limbs[0]);
        let c1 = Literal::u64_suffixed(limbs[1]);
        let c2 = Literal::u64_suffixed(limbs[2]);

From utils/macros-lib/src/lib.rs:201

This test unstable, depending on the build environment

On 2019-08-09 @recmo wrote in 9b150f6 “Add procedural expression macros (#39)”:

This test unstable, depending on the build environment
rustc version?) it requires the single quotes to be escaped or not.

        );
        assert_eq!(
            hex(quote! {123}).to_string(),
            quote! {compile_error ! { "Expected hexadecimal string" }}.to_string()
        );
        // TODO: This test unstable, depending on the build environment
        // (rustc version?) it requires the single quotes to be escaped or not.
        let result = hex(quote! {"hello!"}).to_string();
        let expected_1 = quote! {compile_error ! { "Invalid hexadecimal string: Invalid character 'h' at position 0" }}.to_string();
        let expected_2 = quote! {compile_error ! { "Invalid hexadecimal string: Invalid character \'h\' at position 0" }}.to_string();
        assert!(result == expected_1 || result == expected_2);
    }

From utils/macros-lib/src/lib.rs:274

Inline Keccak256 and work directly on buffer using 'keccakf'

On 2019-09-04 @recmo wrote in f25e929 “Factor proof of work out of channel”:

Inline Keccak256 and work directly on buffer using 'keccakf'

}

impl Challenge {
    pub(crate) fn verify(&self, response: Response) -> bool {
        // TODO: return Result<()>
        // OPT: Inline Keccak256 and work directly on buffer using 'keccakf'
        let mut keccak = Keccak::new_keccak256();
        let mut digest = [0_u8; 32];
        keccak.update(&self.seed);
        keccak.update(&(response.nonce.to_be_bytes()));
        keccak.finalize(&mut digest);

From crypto/openstark/src/proof_of_work.rs:54

Specialize for SliceIterator

On 2019-09-11 @recmo wrote in d715d21 “Update merkle-tree”:

Specialize for SliceIterator

}

impl<T: Clone> Extend<T> for MmapVec<T> {
    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
        // The function signature is for compatibility with Vec::extend.
        // OPT: Specialize for SliceIterator
        for i in iter {
            self.push(i)
        }
    }
}

From utils/mmap-vec/src/mmap_vec.rs:114

Convert 19 digits at a time using u64.

On 2019-04-29 @recmo wrote in b6a0669 “Robust decimal parsing”:

Convert 19 digits at a time using u64.

        if s.is_empty() {
            return Err(ParseError::Empty);
        }
        // TODO: Support other radices
        // TODO: Implement as trait
        // OPT: Convert 19 digits at a time using u64.
        let mut result = Self::ZERO;
        for (i, _c) in s.chars().enumerate() {
            if result > max10 {
                return Err(ParseError::Overflow);
            }

From algebra/u256/src/u256.rs:97

Custom implementation

On 2019-09-11 @recmo wrote in d715d21 “Update merkle-tree”:

Custom implementation

use tempfile::tempfile;

// TODO: Variant of MmapVec where it switched between Vec and Mmap after
//       a treshold size.

#[derive(Debug)] // TODO: Custom implementation
pub struct MmapVec<T: Clone> {
    mmap:     MmapMut,
    length:   usize,
    capacity: usize,
    _t:       PhantomData<T>,

From utils/mmap-vec/src/mmap_vec.rs:18

The zero polynomial is assigned a degree of 0, but it is

On 2019-09-18 @recmo wrote in 52f3e89 “Fix degree function”:

The zero polynomial is assigned a degree of 0, but it is
more correctly left undefined or sometimes assigned -1 or -∞.

    pub fn coefficients(&self) -> &[FieldElement] {
        &self.0
    }

    // TODO: The zero polynomial is assigned a degree of 0, but it is
    // more correctly left undefined or sometimes assigned `-1` or `-∞`.
    pub fn degree(&self) -> usize {
        let mut degree = self.len() - 1;
        while self.0[degree] == FieldElement::ZERO && degree > 0 {
            degree -= 1;
        }

From crypto/openstark/src/polynomial.rs:54

Test optimizing for RHS being exactly 0, 64, 128, ...

On 2019-04-01 @recmo wrote in b1be295 “Finish shearing operations”:

Test optimizing for RHS being exactly 0, 64, 128, ...
Note: Test small values first, they are expected to be more common.

impl ShrAssign<usize> for U256 {
    fn shr_assign(&mut self, rhs: usize) {
        // Note: If RHS is a compile time constant then inlining will allow
        // the branches to be optimized away.
        // TODO: Test optimizing for RHS being exactly 0, 64, 128, ...
        // Note: Test small values first, they are expected to be more common.
        if rhs == 0 {
        } else if rhs < 64 {
            self.c0 >>= rhs;
            self.c0 |= self.c1 << (64 - rhs);
            self.c1 >>= rhs;

From algebra/u256/src/u256.rs:620

Also accept integer literals

On 2019-08-09 @recmo wrote in 9b150f6 “Add procedural expression macros (#39)”:

Also accept integer literals

    .unwrap_or_else(|err: syn::Error| err.to_compile_error())
}

pub fn field_element(input: TokenStream) -> TokenStream {
    (|| {
        // TODO: Also accept integer literals
        let bytes = parse_hex(input)?;
        let limbs = bytes_to_limbs(bytes.as_slice())?;
        let (c0, c1, c2, c3) = montgomery_convert((limbs[0], limbs[1], limbs[2], limbs[3]));
        let c0 = Literal::u64_suffixed(c0);
        let c1 = Literal::u64_suffixed(c1);

From utils/macros-lib/src/lib.rs:219

missing_docs,

On 2019-08-26 @recmo wrote in 84268b4 “Replicate lint rules”:

missing_docs,

    deprecated_in_future,
    elided_lifetimes_in_paths,
    explicit_outlives_requirements,
    keyword_idents,
    macro_use_extern_crate,
    // TODO: missing_docs,
    missing_doc_code_examples,
    private_doc_tests,
    single_use_lifetimes,
    trivial_casts,
    trivial_numeric_casts,

From algebra/u256/src/lib.rs:28

Replace literals with u256h!

On 2019-06-21 @recmo wrote in c447488 “Fix or ignore warnings”:

Replace literals with u256h!

            u64::arbitrary(g),
        )
    }
}

// TODO: Replace literals with u256h!
#[allow(clippy::unreadable_literal)]
// Quickcheck requires pass by value
#[allow(clippy::needless_pass_by_value)]
#[cfg(test)]
mod tests {

From algebra/u256/src/u256.rs:867

clippy::cargo,

On 2019-08-26 @recmo wrote in a9c0949 “Fix lints”:

clippy::cargo,

#![forbid(unsafe_code)]
#![warn(
    // Enable sets of warnings
    clippy::all,
    clippy::pedantic,
    // TODO: clippy::cargo,
    rust_2018_idioms,
    future_incompatible,
    unused,

    // Additional unused warnings (not included in `unused`)

From algebra/u256/src/lib.rs:11

If divq is not supported, use a fast software implementation:

On 2019-04-03 @recmo wrote in a8e0050 “Implement Knuth's divsion algorithm”:

If divq is not supported, use a fast software implementation:
See https://gmplib.org/~tege/division-paper.pdf

/// Compute <hi, lo> / d, returning the quotient and the remainder.
// TODO: Make sure it uses divq on x86_64.
// See http://lists.llvm.org/pipermail/llvm-dev/2017-October/118323.html
// (Note that we require d > hi for this)
// TODO: If divq is not supported, use a fast software implementation:
// See https://gmplib.org/~tege/division-paper.pdf
fn divrem_2by1(lo: u64, hi: u64, d: u64) -> (u64, u64) {
    debug_assert!(d > 0);
    debug_assert!(d > hi);
    let d = u128::from(d);
    let n = val_2(lo, hi);

From algebra/u256/src/division.rs:16

Round up to nearest 4KB

On 2019-09-11 @recmo wrote in d715d21 “Update merkle-tree”:

Round up to nearest 4KB
Note: mmaped files can not be empty, so we use at leas one byte.

impl<T: Clone> MmapVec<T> {
    pub fn with_capacity(capacity: usize) -> Self {
        // From https://docs.rs/tempfile/3.1.0/tempfile/: tempfile() relies on
        // the OS to remove the temporary file once the last handle is closed.
        let file = tempfile().expect("cannot create temporary file");
        // TODO: Round up to nearest 4KB
        // Note: mmaped files can not be empty, so we use at leas one byte.
        let size = max(1, capacity * size_of::<T>());
        info!("Allocating {} MB in temp file", size / 1_000_000);
        file.set_len(size as u64)
            .expect("cannot set mmap file length");
        let mmap = unsafe { MmapOptions::new().len(size).map_mut(&file) }

From utils/mmap-vec/src/mmap_vec.rs:31

Make it store a static ref to an inner allocator (defaults to System)

On 2019-09-11 @recmo wrote in 86e54e2 “Use logging allocator”:

Make it store a static ref to an inner allocator (defaults to System)

    alloc::{GlobalAlloc, Layout, System},
    ptr::null_mut,
    sync::atomic::{AtomicUsize, Ordering::SeqCst},
};

// TODO: Make it store a static ref to an inner allocator (defaults to System)
#[cfg_attr(feature = "std", derive(Debug))]
pub struct LoggingAllocator {
    info:      usize,
    warn:      usize,
    error:     usize,

From utils/logging-allocator/src/lib.rs:47

Copy free implementation. Maybe have index as a leaf type.

On 2019-09-03 @recmo wrote in 17124da “Use merkle_tree for trace commitment”:

Copy free implementation. Maybe have index as a leaf type.

/// Merkle trees over trace table LDE and constraint LDE
// Clippy false positive
#[allow(clippy::use_self)]
impl VectorCommitment for PolyLDE {
    // TODO: Copy free implementation. Maybe have index as a leaf type.
    type Leaf = Vec<U256>;

    fn len(&self) -> usize {
        self.0.first().map_or(0, MmapVec::len)
    }

From crypto/openstark/src/proofs.rs:33

Check performance impact of conversion

On 2019-09-04 @recmo wrote in f25e929 “Factor proof of work out of channel”:

Check performance impact of conversion

        let mut keccak = Keccak::new_keccak256();
        let mut digest = [0_u8; 32];
        keccak.update(&self.seed);
        keccak.update(&(response.nonce.to_be_bytes()));
        keccak.finalize(&mut digest);
        // OPT: Check performance impact of conversion
        let work = U256::from_bytes_be(&digest).leading_zeros();
        work >= self.difficulty
    }
}

From crypto/openstark/src/proof_of_work.rs:60

Avoid initialization

On 2019-09-11 @recmo wrote in 7ced6e0 “Coset parallel LDE”:

Avoid initialization

        let generator =
            FieldElement::root(length).expect("No generator for extended_domain_length.");
        let mut result: MmapVec<FieldElement> = MmapVec::with_capacity(length);

        // Initialize to zero
        // TODO: Avoid initialization
        result.resize(length, FieldElement::ZERO);

        // Compute cosets in parallel
        result
            .as_mut_slice()

From crypto/openstark/src/polynomial.rs:83

Add checks

On 2019-09-10 @recmo wrote in 99f8998 “Layer at a time”:

Add checks

        // assert!(depth < USIZE_BITS);
        1_usize << depth
    }

    pub fn depth_for_size(size: usize) -> usize {
        // TODO: Add checks
        size.next_power_of_two().trailing_zeros() as usize
    }

    pub const fn root() -> Self {
        Self(1)

From crypto/merkle-tree/src/index.rs:50

Drop this in favour of a `const fn` call.

On 2019-08-09 @recmo wrote in 9b150f6 “Add procedural expression macros (#39)”:

Drop this in favour of a const fn call.
These constants are copied, but we don't have u256h! to format them here.

    }
    Ok(result)
}

// This function and constants are taken from primefield::montgomery
// TODO: Drop this in favour of a `const fn` call.
// These constants are copied, but we don't have u256h! to format them here.
#[allow(clippy::unreadable_literal)]
// Variables are relabeled in ways that confuse clippy.
#[allow(clippy::shadow_unrelated)]
fn montgomery_convert(x: (u64, u64, u64, u64)) -> (u64, u64, u64, u64) {
    const M64: u64 = 0xffff_ffff_ffff_ffff;

From utils/macros-lib/src/lib.rs:100

Make member functions of U256?

On 2019-07-09 @recmo wrote in f108f29 “Factor U256 into own crate”:

Make member functions of U256?

// TODO: This seems out of scope for U256 to export.
pub mod utils;

pub use crate::u256::U256;

// TODO: Make member functions of U256?
pub use gcd::{gcd, gcd_extended};
#[cfg(not(feature = "std"))]
extern crate no_std_compat as std;

From algebra/u256/src/lib.rs:50

Why is this wrapping_sub required?

On 2019-08-26 @recmo wrote in a9c0949 “Fix lints”:

Why is this wrapping_sub required?
We want truncation here

/// Compute a - (b * c + borrow), returning the result and the new borrow.
#[inline(always)]
pub const fn msb(a: u64, b: u64, c: u64, borrow: u64) -> (u64, u64) {
    let ret = (a as u128).wrapping_sub((b as u128) * (c as u128) + (borrow as u128));
    // TODO: Why is this wrapping_sub required?
    // We want truncation here
    #[allow(clippy::cast_possible_truncation)]
    (ret as u64, 0_u64.wrapping_sub((ret >> 64) as u64))
}

/// Compute <hi, lo> / d, returning the quotient and the remainder.

From algebra/u256/src/utils.rs:33

Use a proper size human formating function

On 2019-09-10 @recmo wrote in 5ca8487 “Fix clippy”:

Use a proper size human formating function

    let trace = witness.trace(claim);
    let constraints = claim.constraints();

    info!("Starting Stark proof.");
    info!("Proof parameters: {:?}", params);
    // TODO: Use a proper size human formating function
    #[allow(clippy::cast_precision_loss)]
    let size_mb = (trace.num_rows() * trace.num_columns() * 32) as f64 / 1_000_000_f64;
    info!(
        "Trace table {} rows {} columns ({} MB)",
        trace.num_rows(),

From crypto/openstark/src/proofs.rs:124

shift polynomial by FieldElement::GENERATOR outside of this function.

On 2019-09-11 @recmo wrote in e5942ce “Add low_degree_extension to DensePolynomial”:

shift polynomial by FieldElement::GENERATOR outside of this function.

        result
    }

    #[cfg(feature = "std")]
    pub fn low_degree_extension(&self, blowup: usize) -> MmapVec<FieldElement> {
        // TODO: shift polynomial by FieldElement::GENERATOR outside of this function.
        const SHIFT_FACTOR: FieldElement = FieldElement::GENERATOR;
        let length = self.len() * blowup;
        let generator =
            FieldElement::root(length).expect("No generator for extended_domain_length.");
        let mut result: MmapVec<FieldElement> = MmapVec::with_capacity(length);

From crypto/openstark/src/polynomial.rs:75

use single limb version when q is small enough?

On 2019-05-10 @recmo wrote in 84e82c4 “Implement full precision step”:

use single limb version when q is small enough?

    while r1 != U256::ZERO {
        let q = lehmer_double(r0.clone(), r1.clone());
        if q == Matrix::IDENTITY {
            // Do a full precision Euclid step. q is at least a halfword.
            // This should happen zero or one time, seldom more.
            // OPT: use single limb version when q is small enough?
            let q = &r0 / &r1;
            let t = r0 - &q * &r1;
            r0 = r1;
            r1 = t;
            let t = s0 - &q * &s1;

From algebra/u256/src/gcd.rs:389

It may be faster to compute the constraint LDE from the trace LDE,

On 2019-09-19 @recmo wrote in 07b18ab “Implement in-place divide-out-point”:

It may be faster to compute the constraint LDE from the trace LDE,
instead of using an FFT.

            .iter()
            .map(DensePolynomial::degree)
            .collect::<Vec<_>>()
    );

    // OPT: It may be faster to compute the constraint LDE from the trace LDE,
    // instead of using an FFT.
    info!("Compute the low degree extension of constraint polynomials.");
    let constraint_lde = PolyLDE(
        constraint_polynomials
            .par_iter()
            .map(|p| p.low_degree_extension(params.blowup))

From crypto/openstark/src/proofs.rs:189

Ideally we'd locally import U256 here and

On 2019-08-09 @recmo wrote in 9b150f6 “Add procedural expression macros (#39)”:

Ideally we'd locally import U256 here and
use $crate::U256 here, but this leads to a circular
dependency.

        let c0 = Literal::u64_suffixed(limbs[0]);
        let c1 = Literal::u64_suffixed(limbs[1]);
        let c2 = Literal::u64_suffixed(limbs[2]);
        let c3 = Literal::u64_suffixed(limbs[3]);

        // TODO: Ideally we'd locally import U256 here and
        // use $crate::U256 here, but this leads to a circular
        // dependency.
        Ok(quote! { U256::from_limbs(#c0, #c1, #c2, #c3) })
    })()
    .unwrap_or_else(|err: syn::Error| err.to_compile_error())
}

From utils/macros-lib/src/lib.rs:209

Would this be faster using extended binary gcd?

On 2019-06-19 @recmo wrote in ac3a93e “Documentation improvements”:

Would this be faster using extended binary gcd?
We shadow q for readability.

}

/// Compute the Lehmer update matrix for small values.
///
/// This is essentialy Euclids extended GCD algorithm for 64 bits.
// OPT: Would this be faster using extended binary gcd?
// We shadow q for readability.
#[allow(clippy::shadow_unrelated)]
fn lehmer_small(mut r0: u64, mut r1: u64) -> Matrix {
    debug_assert!(r0 >= r1);
    if r1 == 0_u64 {
        return Matrix::IDENTITY;

From algebra/u256/src/gcd.rs:129

Make tests compatible with the proof of work values from this function

On 2019-09-04 @recmo wrote in f25e929 “Factor proof of work out of channel”:

Make tests compatible with the proof of work values from this function

            .map(|nonce| Response { nonce })
            .find(|&response| self.verify(response))
            .expect("No valid nonce found")
    }

    // TODO: Make tests compatible with the proof of work values from this function
    #[cfg(feature = "std")]
    // False positive, constant is used when `std` is set
    #[allow(dead_code)]
    fn solve_threaded(&self) -> Response {
        info!(

From crypto/openstark/src/proof_of_work.rs:88

Can we reuse the shifted variables here?

On 2019-05-10 @recmo wrote in 3231e86 “Implement double-word Lehmer”:

Can we reuse the shifted variables here?

    // We can return q here and have a perfectly valid single-word Lehmer GCD.
    // return q;

    // Recompute r0 and r1 and take the high bits.
    // OPT: This does not need full precision.
    // OPT: Can we reuse the shifted variables here?
    lehmer_update(&mut r0, &mut r1, &q);
    let s = r0.leading_zeros();
    let r0s = r0.clone() << s;
    let r1s = r1.clone() << s;
    let qn = lehmer_loop(r0s.c3, r1s.c3);

From algebra/u256/src/gcd.rs:313

Can be computed in-place

On 2019-04-01 @recmo wrote in 1a554d1 “Add short division”:

Can be computed in-place

            Self::from_limbs(r4, r5, r6, r7),
        )
    }

    // Short division
    // TODO: Can be computed in-place
    pub fn divrem_u64(&self, rhs: u64) -> Option<(Self, u64)> {
        if rhs == 0 {
            None
        } else {
            // Knuth Algorithm S

From algebra/u256/src/u256.rs:254

Variant of MmapVec where it switched between Vec and Mmap after

On 2019-09-11 @recmo wrote in d715d21 “Update merkle-tree”:

Variant of MmapVec where it switched between Vec and Mmap after
a treshold size.

    prelude::v1::*,
    slice,
};
use tempfile::tempfile;

// TODO: Variant of MmapVec where it switched between Vec and Mmap after
//       a treshold size.

#[derive(Debug)] // TODO: Custom implementation
pub struct MmapVec<T: Clone> {
    mmap:     MmapMut,
    length:   usize,

From utils/mmap-vec/src/mmap_vec.rs:15

Naming?

On 2019-08-27 @recmo wrote in 8b9d091 “Starkdex and stark lint fixes”:

Naming?

// TODO: Naming?
#![allow(clippy::module_name_repetitions)]
use mmap_vec::MmapVec;
#[cfg(feature = "std")]
use primefield::fft::{fft_cofactor_permuted, permute_index};
use primefield::FieldElement;

From crypto/openstark/src/polynomial.rs:1

return Option<>

On 2019-04-03 @recmo wrote in 973e638 “Use division in mulmod”:

return Option<>

            Self::from_limbs(numerator[0], numerator[1], 0, 0)
        } else if modulus.c0 > 0 {
            let remainder = divrem_nby1(&mut numerator, modulus.c0);
            Self::from_limbs(remainder, 0, 0, 0)
        } else {
            panic!(); // TODO: return Option<>
        }
    }

    // Computes the inverse modulo 2^256
    pub fn invmod256(&self) -> Option<Self> {

From algebra/u256/src/u256.rs:322

This sequence needs to be repeated in each project.

On 2019-09-11 @recmo wrote in b91e68e:

This sequence needs to be repeated in each project.
See rust-lang/cargo#5034
For clippy lints see: https://rust-lang.github.io/rust-clippy/master
For rustc lints see: https://doc.rust-lang.org/rustc/lints/index.html

// HACK: This sequence needs to be repeated in each project.
//       See https://github.com/rust-lang/cargo/issues/5034
// For clippy lints see: https://rust-lang.github.io/rust-clippy/master
// For rustc lints see: https://doc.rust-lang.org/rustc/lints/index.html
#![cfg_attr(not(feature = "std"), no_std)]
#![forbid(unsafe_code)]
#![warn(
    // Enable sets of warnings
    clippy::all,

From lints.rs:1

use single limb version when q is small enough?

On 2019-05-21 @recmo wrote in a2538fe “Update benchmarks”:

use single limb version when q is small enough?

    while r1 != U256::ZERO {
        let q = lehmer_double(r0.clone(), r1.clone());
        if q == Matrix::IDENTITY {
            // Do a full precision Euclid step. q is at least a halfword.
            // This should happen zero or one time, seldom more.
            // OPT: use single limb version when q is small enough?
            let q = &r0 / &r1;
            let t = r0 - &q * &r1;
            r0 = r1;
            r1 = t;
        } else {

From algebra/u256/src/gcd.rs:343

We can update r0 and r1 in place. This won't remove the partially

On 2019-06-19 @recmo wrote in ac3a93e “Documentation improvements”:

We can update r0 and r1 in place. This won't remove the partially
redundant call to lehmer_update, but it reduces memory usage.
We shadow s for readability.

/// Our approach is similar to Cohen, but instead doing the second round
/// on the same matrix, we start we a fresh matrix and multiply both in the
/// end. This requires 8 additional multiplications, but allows us to use
/// the tighter stopping conditions from Jebelean. It also seems the simplest
/// out of these solutions.
// OPT: We can update r0 and r1 in place. This won't remove the partially
// redundant call to lehmer_update, but it reduces memory usage.
// We shadow s for readability.
#[allow(clippy::shadow_unrelated)]
fn lehmer_double(mut r0: U256, mut r1: U256) -> Matrix {
    debug_assert!(r0 >= r1);
    if r0.bits() < 64 {
        debug_assert!(r1.bits() < 64);

From algebra/u256/src/gcd.rs:290

Generalize over hash implementations.

On 2019-09-02 @recmo wrote in f4f441c “Rename types”:

Generalize over hash implementations.

/// Implements Vector Commitments using Merkle Trees.
///
/// <https://eprint.iacr.org/2011/495.pdf>
// TODO: Spin of to it's own crate.
// TODO: Implement sparse Merkle trees.
// TODO: Generalize over hash implementations.
mod index;
mod node;
mod proof;
mod result;

From crypto/merkle-tree/src/lib.rs:49

Add remainder

On 2019-08-23 @recmo wrote in 5573d5a “Cleanup”:

Add remainder

        assert_eq!(quotient, 1);
    }

    #[quickcheck]
    fn div_3by2_correct(q: u64, d0: u64, d1: u64) -> bool {
        // TODO: Add remainder
        let d1 = d1 | (1 << 63);
        let n = U256::from_limbs(d0, d1, 0, 0) * &U256::from(q);
        debug_assert!(n.c3 == 0);
        let qhat = div_3by2(&[n.c0, n.c1, n.c2], &[d0, d1]);
        qhat == q

From algebra/u256/src/division.rs:258

Why this shift on borrow?

On 2019-04-03 @recmo wrote in b8e7ad6 “Add multiply subtract borrow utility fn”:

Why this shift on borrow?

}

/// Compute a - (b + borrow), returning the result and the new borrow.
#[inline(always)]
pub const fn sbb(a: u64, b: u64, borrow: u64) -> (u64, u64) {
    // TODO: Why this shift on borrow?
    let ret = (a as u128).wrapping_sub((b as u128) + ((borrow >> 63) as u128));
    // We want truncation here
    #[allow(clippy::cast_possible_truncation)]
    (ret as u64, (ret >> 64) as u64)
}

From algebra/u256/src/utils.rs:13

A literal large integer (> u64) would show up as

On 2019-08-09 @recmo wrote in 9b150f6 “Add procedural expression macros (#39)”:

A literal large integer (> u64) would show up as
Lit::Verbatim(v) =>

    let input: Expr = syn::parse2(input)?;
    let result = match input {
        Expr::Lit(expr_lit) => {
            match expr_lit.lit {
                Lit::Str(s) => Some(s),
                // TODO: A literal large integer (> u64) would show up as
                // Lit::Verbatim(v) =>
                _ => None,
            }
        }
        _ => None,
    };

From utils/macros-lib/src/lib.rs:50

We can use macro generated specializations till then.

On 2019-08-26 @recmo wrote in 996bf59 “Add comments”:

We can use macro generated specializations till then.

    debug_assert!(divisor.len() >= 2);
    debug_assert!(numerator.len() > divisor.len());
    debug_assert!(*divisor.last().unwrap() > 0);
    debug_assert!(*numerator.last().unwrap() == 0);
    // OPT: Once const generics are in, unroll for lengths.
    // OPT: We can use macro generated specializations till then.
    let n = divisor.len();
    let m = numerator.len() - n - 1;

    // D1. Normalize.
    let shift = divisor[n - 1].leading_zeros();

From algebra/u256/src/division.rs:102

Simplify

On 2019-09-10 @recmo wrote in 2c2e12a “Fix lints”:

Simplify

    }
}

// False positive: `for<'a>` annotation is required.
#[allow(single_use_lifetimes)]
// TODO: Simplify
#[allow(clippy::cognitive_complexity)]
pub fn stark_proof<Claim: Verifiable, Witness: Provable<Claim>>(
    claim: &Claim,
    witness: &Witness,
    params: &ProofParams,

From crypto/openstark/src/proofs.rs:109

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.