ark-crypto-primitives

repository·main·Indexed 42 days ago

https://github.com/arkworks-rs/crypto-primitives

A collection of Rust libraries providing efficient implementations of cryptographic primitives, including hashes, commitments, signatures, and Merkle trees, specifically designed for use in zkSNARKs. It includes R1CS constraints for these primitives and supports schemes like the Rescue collision-resistant hash. Note: This library is an academic proof-of-concept prototype and is not ready for production use.

Tokens
11.8K
Snippets
35
Records
56
Agent score
54%

What's inside ark-crypto-primitives

  1. Overview of ark-crypto-primitives

    main

    The ark-crypto-primitives repository provides efficient Rust implementations of cryptographic primitives used in zero-knowledge succinct non-interactive arguments (zkSNARKs).

    Key features include:

    • Collision-resistant hash functions
    • Hiding commitments
    • Pseudo-random functions (PRFs)
    • Signatures
    • Optional R1CS constraints for these primitives

    WARNING: This library is an academic proof-of-concept prototype and has not received careful code review. It is NOT ready for production use.

  2. Build and test ark-crypto-primitives

    main

    To build the library, you need the stable Rust toolchain. Ensure rustup is installed, then install the stable toolchain. You can build the library using cargo and run the included unit tests using cargo test to verify the crates.

    # Install the stable Rust toolchain
    rustup install stable
    
    # Clone the repository
    git clone https://github.com/arkworks-rs/crypto-primitives.git
    
    # Build the library in release mode
    cargo build --release
    
    # Run unit tests
    cargo test
  3. Available Sponge Implementations

    main

    The ark-crypto-primitives crate provides several specialized sponge implementations:

    • rescue: Implementation of the Rescue sponge.
    • poseidon: Implementation of the Poseidon sponge (based on Fractal's COS20 implementation).
    • merlin: Implementation of the Merlin sponge.
    • constraints: A module providing the constraint-based counterparts for sponge operations (used in zero-knowledge proof contexts).
  4. Available cryptographic modules in ark-crypto-primitives

    main

    The ark-crypto-primitives crate provides various cryptographic building blocks. Access to these modules is controlled via Cargo features. The available modules are:

    • commitment: Commitment schemes.
    • crh: Cryptographic Hash Functions (CRH).
    • merkle_tree: Merkle Tree implementations.
    • encryption: Encryption primitives.
    • prf: Pseudorandom Functions (PRF).
    • signature: Digital signature schemes.
    • snark: Zero-knowledge SNARK primitives.
    • sponge: Sponge-based constructions.

    To use a specific module, you must enable its corresponding feature in your Cargo.toml.

  5. Supported types for AbsorbGadget

    main

    The following types have built-in implementations of AbsorbGadget, allowing them to be used directly with sponge absorption primitives:

    • Primitive/Basic Types:
      • UInt8<F>
      • Boolean<F>
      • FpVar<F>
    • Elliptic Curve Variables:
      • TEAffineVar<P, F> (Twisted Edwards Affine)
      • SWAffineVar<P, F> (Short Weierstrass Affine)
      • SWProjectiveVar<P, F> (Short Weierstrass Projective)
    • Collections and Wrappers:
      • &[A] (Slices of absorbable items)
      • Vec<A> (Vectors of absorbable items)
      • Option<A> (Note: Option absorption includes a boolean flag indicating if the value was Some)
      • &A (References to absorbable items)
  6. Implement ConfigGadget for Merkle tree constraints

    main

    To use Merkle tree gadgets like PathVar, you must provide a type that implements the ConfigGadget<P, F> trait. This trait defines the relationship between the Merkle tree configuration (P), the field (F), and the specific gadgets used for hashing and compression.

    Required associated types in ConfigGadget:

    • Leaf: The type of the leaf data.
    • LeafDigest: The digest type for leaves (must implement AllocVar, EqGadget, ToBytesGadget, CondSelectGadget, and GR1CSVar).
    • LeafInnerConverter: A DigestVarConverter that converts a LeafDigest into the input type required by the TwoToOneHash gadget.
    • InnerDigest: The digest type for non-leaf nodes.
    • LeafHash: A CRHSchemeGadget that hashes a Leaf into a LeafDigest.
    • TwoToOneHash: A TwoToOneCRHSchemeGadget that compresses two InnerDigest values into one.
  7. Configure a Merkle Tree using the Config trait

    main

    To use the MerkleTree implementation, you must define a type that implements the Config trait. This trait specifies the hashing schemes and data types used at different layers of the tree:

    • Leaf: The type of the raw data being stored (the tree does not store these directly).
    • LeafDigest: The hash output of the leaf layer.
    • LeafInnerDigestConverter: A DigestConverter that transforms a LeafDigest into the input type required by the TwoToOneHash scheme.
    • LeafHash: A CRHScheme that maps Leaf to LeafDigest.
    • InnerDigest: The hash output of the inner layers (must implement Absorb).
    • TwoToOneHash: A TwoToOneCRHScheme that compresses two InnerDigest values into one.
  8. Implement the `Absorb` trait for custom types

    main

    The Absorb trait allows you to define how a type is converted into bytes or field elements so it can be processed by a CryptographicSponge.

    To implement Absorb, you must provide:

    • to_sponge_bytes(&self, dest: &mut Vec<u8>): Appends the object's byte representation to dest.
    • to_sponge_field_elements<F: PrimeField>(&self, dest: &mut Vec<F>): Appends the object's field element representation to dest.

    Alternatively, you can use the #[derive(Absorb)] macro (provided by ark_crypto_primitives_macros) to automatically implement this trait for structs and enums by absorbing their individual fields.

    #[derive(Absorb)]
    struct MyData {
        id: u64,
        value: ark_ff::Fp<...>,
    }
  9. Handle variable-length data with `AbsorbWithLength`

    main

    For types where the length is significant (like lists or strings), implement the AbsorbWithLength trait. This ensures that the length of the data is absorbed before the data itself, preventing collisions between different data structures that might otherwise produce the same byte stream.

    Methods:

    • absorb_length(&self) -> usize: Returns the length of the object.
    • to_sponge_bytes_with_length(&self, dest: &mut Vec<u8>): Appends the length followed by the bytes.
    • to_sponge_field_elements_with_length<F: PrimeField>(&self, dest: &mut Vec<F>): Appends the length as field elements followed by the object's field elements.
  10. Understand DuplexSpongeMode

    main

    The DuplexSpongeMode enum tracks the current operational phase of a duplex sponge, which alternates between absorbing and squeezing.

    Variants:

    • Absorbing { next_absorb_index: usize }: The sponge is in the phase of taking in input data. The next_absorb_index tracks the next position in the state to be XOR-ed.
    • Squeezing { next_squeeze_index: usize }: The sponge is in the phase of outputting data. The next_squeeze_index tracks the next position in the state to be outputted.
    pub enum DuplexSpongeMode {
        Absorbing { next_absorb_index: usize },
        Squeezing { next_squeeze_index: usize },
    }
  11. Initialize and use RescueSponge

    main

    The RescueSponge is a duplex sponge implementation based on the Rescue permutation. It implements the CryptographicSponge and FieldBasedCryptographicSponge traits.

    Workflow:

    1. Initialize: Create a new sponge using RescueSponge::new(&config). The initial state is all zeros and the mode is Absorbing.
    2. Absorb: Use .absorb(input) to ingest data. The input must implement the Absorb trait.
    3. Squeeze: Use the following methods to extract data:
      • .squeeze_bytes(num_bytes): Returns a Vec<u8>.
      • .squeeze_bits(num_bits): Returns a Vec<bool>.
      • .squeeze_field_elements(num_elements): Returns a Vec<F> (native field elements).
      • .squeeze_field_elements_with_sizes(sizes): Returns field elements of varying sizes (useful for non-native field conversions).
    // 1. Setup config
    let config = RescueConfig::<F>::new(...);
    
    // 2. Initialize sponge
    let mut sponge = RescueSponge::new(&config);
    
    // 3. Absorb data
    sponge.absorb(&input_data);
    
    // 4. Squeeze output
    let bytes = sponge.squeeze_bytes(32);
    let elements = sponge.squeeze_field_elements(10);
  12. Absorb multiple values into a sponge using the `absorb!` macro

    main

    The absorb! macro provides a convenient way to absorb multiple different items into a CryptographicSponge in a single statement. Each item in the list must implement the Absorb trait.

    Syntax: absorb!(sponge, item1, item2, ...)

    // Assuming `sponge` is a mutable reference to a CryptographicSponge
    absorb!(sponge, my_u64, my_string, my_struct);