#relation #input #attributes #snark #circuit #object #definition

无std liminal-ark-relation-macro

用于简洁定义SNARK关系的进程宏

4个版本

0.1.3 2023年3月30日
0.1.2 2023年3月24日
0.1.1 2023年3月3日
0.1.0 2023年2月10日

27#relation

Download history 17/week @ 2024-03-30 5/week @ 2024-04-06 13/week @ 2024-04-13 5/week @ 2024-04-20 7/week @ 2024-05-11 2/week @ 2024-05-18

1,012 每月下载次数
liminal-ark-relations 中使用

Apache-2.0

39KB
632

liminal-ark-relation-macro

该软件包提供了用于简洁定义SNARK关系的 snark_relation 进程宏。给定最小关系定义,此宏将生成创建和转换部分关系对象、公共输入序列化和电路生成的所有必需代码。

一般用法

#[snark_relation] 属性适用于模块。此类模块必须定义两个项目

  1. 关系对象:所有常量、公共和私有关系数据的集合。该结构必须使用 #[relation_object_definition] 属性定义。所有其他属性都将保留。
  2. 电路定义:电路形式。必须使用#[circuit_definition]属性来定义功能。签名可以是任意的:函数体将在ark_relations::r1cs::ConstraintSynthesizer特质实现中使用。所有功能属性(如功能门控或linting)都保留,并在impl级别添加。

提供这些输入后,宏将生成以下项目(在模块外部)。

  • 三个新的公共结构体:<R>WithoutInput<R>WithPublicInput<R>WithFullInput,其中<R>是关系对象结构的名称。第一个将只有常量作为其字段,第二个将另外包含公共输入,最后一个将包含所有数据。
  • 每个结构体的new(..)构造函数。重要:构造函数参数的顺序是:所有常量,然后是公共输入,最后是私有输入。每个组中的顺序从关系对象定义继承。
  • 字段的获取器。对于常量,签名是fn <field>(&self) -> &<field_type>。对于公共和私有输入,签名是fn <field>(&self) -> Result<&<field_type>, SynthesisError>。所有结构体都有相同的获取器集合。当字段缺失时,返回SynthesisError::MissingAssignment
  • <R>WithFullInput<R>WithPublicInput和从<R>WithPublicInput<R>WithoutInput的转换。
  • <R>WithPublicInput提供serialize_public_input(&self)方法。
  • <R>WithoutInput实现ConstraintSynthesizer特质(带设置模式检查)。
  • <R>WithFullInput实现ConstraintSynthesizer特质。
#[snark_relation]
mod relation {
    #[relation_object_definition]
    struct SomeRelation {
        #[constant]
        a: CF,
        #[public_input]
        b: CF,
        #[private_input]
        c: CF,
    }

    #[circuit_definition]
    fn generate_circuit() -> ark_relations::r1cs::Result<()> {
        Ok(())
    }
}

模块中存在的所有导入(use项)将被复制并移至外部(与生成项一起)。

字段属性

字段可以具有额外的修饰符。常量和私有输入可以增强为

  • 前端类型(例如:#[private_input(frontend_type = "u32")])-这指定了构造函数中应该期望的类型。然后将从前端值创建项目类型(后端类型),并在以后使用。
  • 前端值解析器(例如:#[private_input(frontend_type = "u32", parse_with = "u32_to_CF")])-这是用于将前端值转换为构造函数中的后端类型的方法。除非指定,否则将使用 .into()。它不能在没有 frontend_type 的情况下使用。

公共输入可以有一个额外的修饰符

  • 序列化器(例如:#[public_input(serialize_with = "flatten_sequence")])-序列化过程应产生 Vec<CF>(其中 CF 是电路字段类型)。默认情况下,每个公共输入都将首先封装成一个单例向量(vec![input]),然后,按顺序的结果将使用 .concat() 进行展开。如果你的输入需要其他方式来适应(通常是展开),你可以传递你自定义的序列化器。

修饰符中的所有值(函数名称、类型)都必须以字符串字面量(在 "" 内)传递。

use ark_std::{One, Zero};
use snark_relation_proc_macro::snark_relation;

use crate::CircuitField;

fn parse_u16(x: u16) -> CircuitField {
   CircuitField::from(x)
}

fn byte_to_bits<F: Zero + One + Copy>(byte: &u8) -> Vec<F> {
   let mut bits = [F::zero(); 8];
   for (idx, bit) in bits.iter_mut().enumerate() {
       if (byte >> idx) & 1 == 1 {
           *bit = F::one();
       }
   }
   bits.to_vec()
}

#[snark_relation]
mod relation {
   #[relation_object_definition]
   struct SomeRelation {
       #[constant]
       a: u8,
       #[public_input(frontend_type = "u16", parse_with = "parse_u16")]
       b: CF,
       #[private_input(frontend_type = "u32")]
       c: u64,
       #[public_input(serialize_with = "byte_to_bits")]
       d: u8,
   }

   #[circuit_definition]
   fn generate_circuit() -> ark_relations::r1cs::Result<()> {
       Ok(())
   }
}

依赖项

~2MB
~42K SLoC