edwards25519 point压缩及解压缩算法

edwards25519 curve表示为:

− x 2 + y 2 = 1 + d x 2 y 2 , d = − ( 121665 / 121666 ) , q = 2 255 − 19 -x^2+y^2=1+dx^2y^2,d=-(121665/121666),q=2^{255}-19 x2+y2=1+dx2y2,d=(121665/121666),q=225519
⇒ x 2 = ( y 2 − 1 ) / ( d y 2 + 1 )   ( m o d   q ) \Rightarrow x^2=(y^2-1)/(dy^2+1)\ (mod\ q) x2=(y21)/(dy2+1) (mod q)

0. 为何edwards curve point可以压缩

根据论文《Twisted Edwards Curves Revisited》有:
在这里插入图片描述
可知 ( − x , y ) + ( x , y ) = ( 0 , 1 ) = ∞ (-x,y)+(x,y)=(0,1)=\infty (x,y)+(x,y)=(0,1)=
所以, ( 0 , 1 ) (0,1) (0,1)不在 F p F_p Fp subgroup中(其中,对于Curve25519, p = 8 q , q = 2 252 + 27742317777372353535851937790883648493 p=8q,q=2^{252} + 27742317777372353535851937790883648493 p=8q,q=2252+27742317777372353535851937790883648493)。
因此: ( − x , y ) 和 ( x , y ) (-x,y)和(x,y) (x,y)(x,y)不可以同时在同一个subgroup中,于是可以直接取 y y y坐标和 x x x坐标的符号位来表示唯一点。

以上内容参考https://ethresear.ch/t/some-snarky-tricks-from-ethboston-zeropool-under-the-hood/6115:(dalek-Curve25519中的压缩算法采用是 ( − x , y ) 和 ( x , y ) (-x,y)和(x,y) (x,y)(x,y),github.com/snjax/circomlib中采用的压缩算法是 ( x , y ) 和 ( x , − y ) (x,y)和(x,-y) (x,y)(x,y))。
在这里插入图片描述

1. compression压缩算法

将edwards25519的point ( x , y ) (x,y) (x,y),其中每个 x , y x,y x,y均可以little-endian数组[u8;32]表示,表示一个point 需要2个[u8;32]数组。
通过压缩算法,可用一个[u8;32]数组来表示point ( x , y ) (x,y) (x,y)。具体的压缩算法为:
E n c ( x , y ) = ( y ∣ x &lt; &lt; 255 ) Enc(x,y)=(y|x&lt;&lt;255) Enc(x,y)=(yx<<255)

根据ed25519中约定可知, x &lt; &lt; 255 x&lt;&lt;255 x<<255即为 x x x的最低有效位,若为1代表的是负数,若为0则代表的是非负数。

通过压缩算法,可有效减少存储空间。

python脚本为:

def point_compress(P):
    zinv = modp_inv(P[2])
    x = P[0] * zinv % p
    y = P[1] * zinv % p
    return int.to_bytes(y | ((x & 1) << 255), 32, "little")

curve25519-dalek中的代码为:

/// Compress this point to `CompressedEdwardsY` format.
    pub fn compress(&self) -> CompressedEdwardsY {
        let recip = self.Z.invert();
        let x = &self.X * &recip;
        let y = &self.Y * &recip;
        let mut s: [u8; 32];

        s = y.to_bytes();
        s[31] ^= x.is_negative().unwrap_u8() << 7;
        CompressedEdwardsY(s)
    }

2. decompression解压缩算法

对于收到的 e = E n c ( x , y ) = ( y ∣ x &lt; &lt; 255 ) e=Enc(x,y)=(y|x&lt;&lt;255) e=Enc(x,y)=(yx<<255),其中 e e e的最高位即为 x 0 x_0 x0值,有:
x 0 = e &gt; &gt; 255 x_0=e&gt;&gt;255 x0=e>>255
y = e &amp; ( 2 255 − 1 ) y=e\&amp;(2^{255}-1) y=e&(22551)

由此可见 y y y值直接可知,需要根据公式 x 2 = ( y 2 − 1 ) / ( d y 2 + 1 )   ( m o d   q ) x^2=(y^2-1)/(dy^2+1)\ (mod\ q) x2=(y21)/(dy2+1) (mod q)来恢复 x x x值。正常有两个根,根据 x 0 x_0 x0来选择正确的那个根。

根据博客有限域内的平方根求解原理解析及curve25519-dalek中的实现来求解即可。

python脚本为:

	/// Attempt to decompress to an `EdwardsPoint`.
    ///
    /// Returns `None` if the input is not the \\(y\\)-coordinate of a
    /// curve point.
    pub fn decompress(&self) -> Option<EdwardsPoint> {
        let Y = FieldElement::from_bytes(self.as_bytes());
        let Z = FieldElement::one();
        let YY = Y.square();
        let u = &YY - &Z;                            // u =  y²-1
        let v = &(&YY * &constants::EDWARDS_D) + &Z; // v = dy²+1
        let (is_valid_y_coord, mut X) = FieldElement::sqrt_ratio_i(&u, &v);

        if is_valid_y_coord.unwrap_u8() != 1u8 { return None; }

        // Flip the sign of X if it's not correct
        let compressed_sign_bit = Choice::from(self.as_bytes()[31] >> 7);
        let    current_sign_bit = X.is_negative();

        X.conditional_negate(current_sign_bit ^ compressed_sign_bit);

        Some(EdwardsPoint{ X: X, Y: Y, Z: Z, T: &X * &Y })
    }

参考资料:
[1] Edwards-Curve Digital Signature Algorithm (EdDSA)
[2] ed25519
[3] 有限域内的平方根求解原理解析及curve25519-dalek中的实现
[4] Extended twisted Edwards curve坐标系
[6] https://ethresear.ch/t/some-snarky-tricks-from-ethboston-zeropool-under-the-hood/6115

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值