curve25519-dalek中的MontgomeryPoint及与Scalar乘积

2023-10-24 15:30

本文主要是介绍curve25519-dalek中的MontgomeryPoint及与Scalar乘积,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. Curve25519定义

The Curve25519 function is Fp-restricted x-coordinate scalar multiplication on E(Fp2 ), where p is the prime number p = 2255 − 19 and E is the elliptic curve y2 = x3 + 486662x2 + x.
对应的base point为(9,…)。
The order of the base point is a prime,
namely 2252 + 27742317777372353535851937790883648493.
FieldElement对应的域空间为[0, p-1),即为[0, 2255-19 - 1)。

https://github.com/dalek-cryptography/curve25519-dalek/blob/master/src/montgomery.rs 中的相应定义为

pub struct MontgomeryPoint(pub [u8;32]); //采用little-endian方式存储。/// The X25519 basepoint, in `MontgomeryPoint` format.
pub const X25519_BASEPOINT: MontgomeryPoint =MontgomeryPoint([0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);/// `BASEPOINT_ORDER` is the order of the Ristretto group and of the Ed25519 basepoint, i.e.,
/// $$
/// \ell = 2^\{252\} + 27742317777372353535851937790883648493.
/// $$
/// sage: hex(2^252+27742317777372353535851937790883648493)
/// '1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed'
pub const BASEPOINT_ORDER: Scalar = Scalar{bytes: [0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,],
};

2. MontgomeryPoint*Scalar

/// Multiply this `MontgomeryPoint` by a `Scalar`.
impl<'a, 'b> Mul<&'b Scalar> for &'a MontgomeryPoint {type Output = MontgomeryPoint;/// Given `self` \\( = u\_0(P) \\), and a `Scalar` \\(n\\), return \\( u\_0([n]P) \\).fn mul(self, scalar: &'b Scalar) -> MontgomeryPoint {// Algorithm 8 of Costello-Smith 2017。此处采用的是《Montgomery curves and their arithmetic》论文中的算法8。let affine_u = FieldElement::from_bytes(&self.0); // 将[u8; 32]转换位[u64; 5]数组,且数组内每个元素仅存储51个bit。let mut x0 = ProjectivePoint::identity(); //采用O和P点作为基础点,可保证loop为constant lenght.具体原因参见https://blog.csdn.net/mutourend/article/details/96426020let mut x1 = ProjectivePoint {U: affine_u, //XW: FieldElement::one(), //Z,归一化了};let bits: [i8; 256] = scalar.bits(); //将[u8;32]转换为二进制位按little-endian形式存储[i8;256],虽然用的i8,其实元素只为0或1。for i in (0..255).rev() { //254~0。scalar的bitlen l=256,循环的范围是从l-2~0let choice: u8 = (bits[i + 1] ^ bits[i]) as u8; //异或debug_assert!(choice == 0 || choice == 1); //保证bits中存储的元素仅为0或1.ProjectivePoint::conditional_swap(&mut x0, &mut x1, choice.into());differential_add_and_double(&mut x0, &mut x1, &affine_u);}ProjectivePoint::conditional_swap(&mut x0, &mut x1, Choice::from(bits[0] as u8));x0.to_affine() //将输入(X:Z),转换为:$x=X/Z$,以[u8;32]格式存储。}
}

其中FieldElement的定义如下:
FieldElement用数组形式存储[u64;5],因为Curve25519的p为2255-19,所以FieldElement每个数组元素仅需要用其中的51位即可,分别均匀的存储在5个元素中,即可表示域p内的所有值。

/// A `FieldElement` represents an element of the field
/// \\( \mathbb Z / (2\^{255} - 19)\\).
///
/// The `FieldElement` type is an alias for one of the platform-specific
/// implementations.
#[cfg(feature = "u64_backend")]
pub type FieldElement = backend::serial::u64::field::FieldElement51;pub struct FieldElement51(pub (crate) [u64; 5]);/// Load a `FieldElement51` from the low 255 bits of a 256-bit //256位是因为输入位[u8; 32] = 32*8 = 256 bit。/// input./// 因为p=2^255-19,所以(2^255 - 18) mod p = 1/// # Warning////// This function does not check that the input used the canonical/// representative.  It masks the high bit, but it will happily/// decode 2^255 - 18 to 1.  Applications that require a canonical/// encoding of every field element should decode, re-encode to/// the canonical encoding, and check that the input was/// canonical.///pub fn from_bytes(bytes: &[u8; 32]) -> FieldElement51 {let load8 = |input: &[u8]| -> u64 {(input[0] as u64)| ((input[1] as u64) << 8)| ((input[2] as u64) << 16)| ((input[3] as u64) << 24)| ((input[4] as u64) << 32)| ((input[5] as u64) << 40)| ((input[6] as u64) << 48)| ((input[7] as u64) << 56)};let low_51_bit_mask = (1u64 << 51) - 1;FieldElement51( //将[u8; 32]转换位[u64; 5]数组,且数组内每个元素仅存储51个bit。// load bits [  0, 64), no shift[  load8(&bytes[ 0..])        & low_51_bit_mask// load bits [ 48,112), shift to [ 51,112), (load8(&bytes[ 6..]) >>  3) & low_51_bit_mask// load bits [ 96,160), shift to [102,160), (load8(&bytes[12..]) >>  6) & low_51_bit_mask// load bits [152,216), shift to [153,216), (load8(&bytes[19..]) >>  1) & low_51_bit_mask// load bits [192,256), shift to [204,112), (load8(&bytes[24..]) >> 12) & low_51_bit_mask])}/// Construct zero.pub fn zero() -> FieldElement51 {FieldElement51([ 0, 0, 0, 0, 0 ])}/// Construct one.pub fn one() -> FieldElement51 {FieldElement51([ 1, 0, 0, 0, 0 ])}

ProjectivePoint的定义如下:
其中ProjectivePoint的对应的是F映射(见Montgomery curve的运算(1)——add/double运算 第2节说明)
F : P ↦ { ( x p : 1 ) i f P = ( x p : y p : 1 ) ( 1 : 0 ) i f P = O = ( 0 : 1 : 0 ) F:P\mapsto\left\{\begin{matrix} (x_p:1) &amp; if &amp;P=(x_p:y_p:1) \\ (1:0)&amp; if &amp;P=O=(0:1:0) \end{matrix}\right. F:P{(xp:1)(1:0)ififP=(xp:yp:1)P=O=(0:1:0)
F ( ( X : Y : Z ) ) = ( X : Z ) F((X:Y:Z))=(X:Z) F((X:Y:Z))=(X:Z)仅对Z!=0的情况成立。

/// A `ProjectivePoint` holds a point on the projective line
/// \\( \mathbb P(\mathbb F\_p) \\), which we identify with the Kummer
/// line of the Montgomery curve.
#[derive(Copy, Clone, Debug)]
struct ProjectivePoint {pub U: FieldElement,pub W: FieldElement,
}impl Identity for ProjectivePoint {fn identity() -> ProjectivePoint {ProjectivePoint {U: FieldElement::one(),W: FieldElement::zero(),}}
}

let bits: [i8; 256] = scalar.bits();对应为:

	/// Get the bits of the scalar.pub(crate) fn bits(&self) -> [i8; 256] { //将[u8;32]转换为二进制位按little-endian形式存储[i8;256],虽然用的i8,其实元素只为0或1。let mut bits = [0i8; 256];for i in 0..256 {// As i runs from 0..256, the bottom 3 bits index the bit,// while the upper bits index the byte.bits[i] = ((self.bytes[i>>3] >> (i&7)) & 1u8) as i8; //每个byte内共8个bit元素,元素编号为从0~7,所以需要i>>3和i&7}bits}/// The `Scalar` struct holds an integer \\(s < 2\^{255} \\) which
/// represents an element of \\(\mathbb Z / \ell\\).
#[derive(Copy, Clone)]
pub struct Scalar {/// `bytes` is a little-endian byte encoding of an integer representing a scalar modulo the/// group order.////// # Invariant////// The integer representing this scalar must be bounded above by \\(2\^{255}\\), or/// equivalently the high bit of `bytes[31]` must be zero.////// This ensures that there is room for a carry bit when computing a NAF representation.//// XXX This is pub(crate) so we can write literal constants.  If const fns were stable, we could//     make the Scalar constructors const fns and use those instead.pub(crate) bytes: [u8; 32],
}

differential_add_and_double中,将xADDxDBL放一个函数内实现,进一步优化了执行效率。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

/// Perform the double-and-add step of the Montgomery ladder.
///
/// Given projective points
/// \\( (U\_P : W\_P) = u(P) \\),
/// \\( (U\_Q : W\_Q) = u(Q) \\),
/// and the affine difference
/// \\(      u\_{P-Q} = u(P-Q) \\), set
/// $$
///     (U\_P : W\_P) \gets u([2]P)
/// $$
/// and
/// $$
///     (U\_Q : W\_Q) \gets u(P + Q).
/// $$
fn differential_add_and_double(P: &mut ProjectivePoint,Q: &mut ProjectivePoint,affine_PmQ: &FieldElement,
) {let t0 = &P.U + &P.W;let t1 = &P.U - &P.W;let t2 = &Q.U + &Q.W;let t3 = &Q.U - &Q.W;let t4 = t0.square();   // (U_P + W_P)^2 = U_P^2 + 2 U_P W_P + W_P^2let t5 = t1.square();   // (U_P - W_P)^2 = U_P^2 - 2 U_P W_P + W_P^2let t6 = &t4 - &t5;     // 4 U_P W_Plet t7 = &t0 * &t3;     // (U_P + W_P) (U_Q - W_Q) = U_P U_Q + W_P U_Q - U_P W_Q - W_P W_Qlet t8 = &t1 * &t2;     // (U_P - W_P) (U_Q + W_Q) = U_P U_Q - W_P U_Q + U_P W_Q - W_P W_Qlet t9  = &t7 + &t8;    // 2 (U_P U_Q - W_P W_Q)let t10 = &t7 - &t8;    // 2 (W_P U_Q - U_P W_Q)let t11 =  t9.square(); // 4 (U_P U_Q - W_P W_Q)^2let t12 = t10.square(); // 4 (W_P U_Q - U_P W_Q)^2let t13 = &APLUS2_OVER_FOUR * &t6; // (A + 2) U_P U_Qlet t14 = &t4 * &t5;    // ((U_P + W_P)(U_P - W_P))^2 = (U_P^2 - W_P^2)^2let t15 = &t13 + &t5;   // (U_P - W_P)^2 + (A + 2) U_P W_Plet t16 = &t6 * &t15;   // 4 (U_P W_P) ((U_P - W_P)^2 + (A + 2) U_P W_P)let t17 = affine_PmQ * &t12; // U_D * 4 (W_P U_Q - U_P W_Q)^2let t18 = t11;               // W_D * 4 (U_P U_Q - W_P W_Q)^2P.U = t14;  // U_{P'} = (U_P + W_P)^2 (U_P - W_P)^2P.W = t16;  // W_{P'} = (4 U_P W_P) ((U_P - W_P)^2 + ((A + 2)/4) 4 U_P W_P)Q.U = t18;  // U_{Q'} = W_D * 4 (U_P U_Q - W_P W_Q)^2Q.W = t17;  // W_{Q'} = U_D * 4 (W_P U_Q - U_P W_Q)^2
}

to_affine函数将输入(X:Z),转换为: x = X / Z x=X/Z x=X/Z,以[u8;32]格式存储。

impl ProjectivePoint {/// Dehomogenize this point to affine coordinates.////// # Return////// * \\( u = U / W \\) if \\( W \neq 0 \\);/// * \\( 0 \\) if \\( W \eq 0 \\);pub fn to_affine(&self) -> MontgomeryPoint {let u = &self.U * &self.W.invert(); //此处invert为FieldElement内的invert,乘积为两个FieldElement的乘积。MontgomeryPoint(u.to_bytes())}
}

3. Scalar*MontgomeryPoint

impl<'a, 'b> Mul<&'b MontgomeryPoint> for &'a Scalar {type Output = MontgomeryPoint;fn mul(self, point: &'b MontgomeryPoint) -> MontgomeryPoint {point * self //转换调用2算法,MontgomeryPoint*Scalar}
}

4. MontgomeryPoint *=Scalar

impl<'b> MulAssign<&'b Scalar> for MontgomeryPoint {fn mul_assign(&mut self, scalar: &'b Scalar) {*self = (self as &MontgomeryPoint) * scalar; //转换调用2算法,MontgomeryPoint*Scalar}
}

参考资料:
[1] 论文《Montgomery curves and their arithmetic》

这篇关于curve25519-dalek中的MontgomeryPoint及与Scalar乘积的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/276096

相关文章

每日一题,力扣leetcode Hot100之238.除自身以外数组的乘积

乍一看这个题很简单,但是不能用除法,并且在O(N)时间复杂度完成或许有点难度。 考虑到不能用除法,如果我们要计算输出结果位置i的值,我们就要获取这个位置左边的乘积和右边的乘积,那么我新设立两个数组L和R。 对于L来说,由于表达的是位置i左边的数的乘积,那么L[0]=1,因为第一个数字左边没数那么为了不影响乘积初始值就设置为1,那么L[1]=L[0]*nums[0],那么L[i]=L[i-1

Leetcode 152. 乘积最大子数组(Medium)

给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续  子数组 (该子数组中至少包含一个数字),并返回该子数组所对应的乘积。 测试用例的答案是一个 32-位 整数。 示例 1: 输入: nums = [2,3,-2,4]输出: 6解释: 子数组 [2,3] 有最大乘积 6。 示例 2: 输入: nums = [-2,0,-1]输出: 0解释: 结果不能为 2,

张量乘积运算实例

a = torch.tensor([[1, 2, 2], [3, 4, 4]])b = torch.tensor([[1, 2, 2], [3, 4, 4], [5, 6, 6]]) 张量a的维度是2x3,张量b的维度是3x3。根据矩阵乘法的规则,a的列数(3)与b的行数(3)相等,所以这两个张量可以进行矩阵乘法运算。 矩阵乘法的结果c的维度将是a的行数乘以b的列数,即2x3矩阵乘以3x3

【Derivation】Kronecker乘积

Kronecker乘积 矩阵之间的Kronecker积是一种新的矩阵运算,起源于群论点击打开链接,物理上用来研究粒子理论。 Now,我们用它来研究矩阵方程,表示十分简洁,研究矩阵微积分运算时也要用到。 设 A=(aij)∈Pm∗n,B=(bij)∈Pp∗q

NC 三个数的最大乘积

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 描述 给定一个长度为 n 的无序数组 A ,包含正数、负数和 0 ,请从中找出 3 个数,使得乘积最大,返回这个乘积。 import java.util.*;publi

有向无环图的关联矩阵及其矩阵乘积的含义

有向无环图的关联矩阵及其矩阵乘积的含义 引言关联矩阵的定义矩阵乘积 B B T BB^T BBT的含义伪代码示例C代码示例结论 引言 在计算机科学和数学中,有向无环图(Directed Acyclic Graph, DAG)是一种常见的数据结构,广泛应用于各种算法中,如拓扑排序、动态规划等。在有向无环图中,关联矩阵(incidence matrix)是一种表示图中顶点与边之间关系

深度学习100问39:阿达玛乘积在实际生活中的应用

嘿,你知道吗?阿达玛乘积在我们的生活中可有着不少神奇的应用呢!   一、图像处理领域   在图像处理的世界里,阿达玛乘积就像是一个神奇的画笔。比如说图像融合吧,想象一下,你有两张超酷的照片,一张是美丽的风景照,另一张是带有超炫艺术滤镜的图片。通过阿达玛乘积,就好像让这两张照片上的每个小像素都来一场“亲密合作”。结果呢,你就得到了一张既有清晰风景又带有独特艺术风格的全新照片,是不是很神奇?还有在计算

前n个素数的乘积表

1, 2, 6, 30, 210, 2310, 30030, 510510, 9699690, 223092870, 6469693230, 200560490130, 7420738134810, 304250263527210, 13082761331670030, 614889782588491410

乘积最大---区间型dp

题目描述 Description 今年是国际数学联盟确定的“2000——世界数学年”,又恰逢我国著名数学家华罗庚先生诞辰90周年。在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一个好朋友XZ也有幸得以参加。活动中,主持人给所有参加活动的选手出了这样一道题目:   设有一个长度为N的数字串,要求选手使用K个乘号将它分成K+1个部分,找出一种分法,使得这K+1个部分的

【剑指offer】构建乘积数组(数组)

题目描述 给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…*A[i-1]A[i+1]…*A[n-1]。不能使用除法。 链接 https://www.nowcoder.com/practice/94a4d381a68b47b7a8bed86f2975db46?tpId=13&tqId=11204&rp=1&ru=/ta/c