在密碼學的運算中, 數字通常是非常大的. 以 ECDSA 橢圓曲線為例, 私鑰是 256 位的.
所以在 libsecp256k1 這個庫里, 定義了計算的元素 Field. 其中 n 為 320 位.
pub struct Field {
pub(crate) n: [u32; 10],
pub(crate) magnitude: u32,
pub(crate) normalized: bool,
}
為其實現加法運算符, 即 Add 和 AddAssign 特征:
impl AddAssign for Field {
fn add_assign(&mut self, other: &'a Field) {
self.n[0] += other.n[0];
self.n[1] += other.n[1];
self.n[2] += other.n[2];
self.n[3] += other.n[3];
self.n[4] += other.n[4];
self.n[5] += other.n[5];
self.n[6] += other.n[6];
self.n[7] += other.n[7];
self.n[8] += other.n[8];
self.n[9] += other.n[9];
self.magnitude += other.magnitude;
self.normalized = false;
debug_assert!(self.verify());
}
}
在 rust 里, 想要讓某個 struct 可以進行某種運算, 例如加法, 只需要實現對應的 Trait 即可, 非常方便. 另外, 每種 Trait 的標識包括名稱和類型簽名. 一樣的名稱, 可以有不一樣的類型簽名.
小貼士: 這里 debug_assert! 宏是只在未開啟優化的編譯包中才有效.
Field 可以被壓縮成 FieldStorage, 也就是我們常見的 256 位. 便于存儲.
pub struct FieldStorage(pub [u32; 8]);
impl Into for Field {
fn into(self) -> FieldStorage {
debug_assert!(self.normalized);
let mut r = FieldStorage::default();
r.0[0] = self.n[0] | self.n[1] << 26;
...
r
}
}
小貼士: 定義 struct 的時候可以用上面這種方法直接以 tuple 作為項.