Mina Learning - Signature

  • longerd
  • 更新于 5天前
  • 阅读 170

Mina 采用 Schnorr signature 生成签名.

Schnorr signature

sign

输入 kp=(sk, pk), input 输出签名 sig=(s, R.x)

  1. 使用 derive_nonce(kp, msg) 生成随机数 k
  2. 计算 $R = k \cdot g$
  3. 判断 R.x 是否是偶数, 否则 k = -k
  4. 计算 e = H(pk, R.x, input)
  5. 计算签名 s = k + e * sk

verify

输入 sig, pk, msg 输出: bool

  1. 计算 e = H(pk, R.x, input)
  2. 计算 $S = s \cdot g$
  3. 计算 $R'= S - e \cdot pk $
  4. 判断 R'.y 是偶数且 R'.x=R.x

derive_nonce

  1. Blake2bVar(input, pk.x, pk.y, sk, domain_param)
  2. 将 hash 值高两位置0(因为 Scalar 是255位, 高两位置0, 能保证 hash 值一定在 Scalar域内)
  3. 将处理后的 hash 值转成 Scalar k
    /// This function uses a cryptographic hash function to create a uniformly and
    /// randomly distributed nonce.  It is crucial for security that no two different
    /// messages share the same nonce.
    fn derive_nonce(&self, kp: &Keypair, input: &H) -> ScalarField {
        let mut blake_hasher = Blake2bVar::new(32).unwrap();

        let roi = input
            .to_roinput()
            .append_field(kp.public.point().x)
            .append_field(kp.public.point().y)
            .append_scalar(*kp.secret.scalar())
            .append_bytes(&self.domain_param.clone().into_bytes());

        blake_hasher.update(&roi.to_bytes());

        let mut bytes = [0; 32];
        blake_hasher
            .finalize_variable(&mut bytes)
            .expect("incorrect output size");
        // Drop the top two bits to convert into a scalar field element
        //   N.B. Since the order of Pallas's scalar field p is very close to 2^m
        //   for some m, truncating only creates a tiny amount of bias that should
        //   be insignificant and better than reduction modulo p.
        bytes[bytes.len() - 1] &= 0b0011_1111;

        ScalarField::from_random_bytes(&bytes[..]).expect("failed to create scalar from bytes")
    }

message_hash

  1. poseidon(input, pk.x, pk.y, R.x)
  2. hash 值转成 Scalar(涉及到 Base 域的值转 Scalar 域)
    fn message_hash(&mut self, pub_key: &PubKey, rx: BaseField, input: &H) -> ScalarField {
        let schnorr_input = Message::<H> {
            input: input.clone(),
            pub_key_x: pub_key.point().x,
            pub_key_y: pub_key.point().y,
            rx,
        };

        // Squeeze and convert from base field element to scalar field element
        // Since the difference in modulus between the two fields is < 2^125, w.h.p., a
        // random value from one field will fit in the other field.
        ScalarField::from(self.hasher.hash(&schnorr_input).into_bigint())
    }

Poseidon

Mina hash 主要使用 Poseidon, 主要原因应该是 Poseidon zk-friendly, 生成电路约束较(SHA256, Keccak256 ...)少.

Mina 使用下面两种, 区别是 Poseidon 参数不同. 详细请看 params.sage.

pub(crate) fn create_legacy<H: 'static + Hashable>(domain_param: H::D) -> impl Signer<H> {
    Schnorr::<H> {
        hasher: Box::new(mina_hasher::create_legacy::<Message<H>>(
            domain_param.clone(),
        )),
        domain_param,
    }
}

pub(crate) fn create_kimchi<H: 'static + Hashable>(domain_param: H::D) -> impl Signer<H> {
    Schnorr::<H> {
        hasher: Box::new(mina_hasher::create_kimchi::<Message<H>>(
            domain_param.clone(),
        )),
        domain_param,
    }
}
点赞 2
收藏 1
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
longerd
longerd
code longer