2021SC@SDUSC
secp256k1的結構——私鑰
- 私鑰SecretKey
- 私鑰生成
- 私鑰反序列化
- 私鑰序列化
結構體SecretKey表示私鑰,私鑰就是一個標量:
pub struct SecretKey(Scalar);
在libsecp256k1中的私鑰共256位元,也就是32位元組:
pub const SECRET_KEY_SIZE: usize = 32;//私鑰共32位元組
私鑰SecretKey
下面是私鑰相關的函式實作,主要包括私鑰生成、私鑰反序列化和私鑰序列化,上一篇講的公鑰要通過私鑰來生成,而這里的私鑰要通過隨機生成(這里的隨機是指偽隨機,因為純軟體(也就是僅靠代碼)是無法實作真正的隨機的),私鑰的序列化和反序列化與公鑰就不一樣了,因為公鑰是Field,而私鑰是Scalar,由于哈希摘要也是Scalar,并且同為256位元,這里呼叫的序列化和反序列化函式其實是一樣的,但在細節上有些不同,
impl SecretKey {
//反序列化私鑰
pub fn parse(p: &[u8; util::SECRET_KEY_SIZE]) -> Result<SecretKey, Error> {
let mut elem = Scalar::default();
if !bool::from(elem.set_b32(p)) {
Self::try_from(elem)
} else {
Err(Error::InvalidSecretKey)
}
}
pub fn parse_slice(p: &[u8]) -> Result<SecretKey, Error> {
if p.len() != util::SECRET_KEY_SIZE {
return Err(Error::InvalidInputLength);
}
let mut a = [0; 32];
a.copy_from_slice(p);
Self::parse(&a)
}
//私鑰生成
pub fn random<R: Rng>(rng: &mut R) -> SecretKey {
loop {
let mut ret = [0u8; util::SECRET_KEY_SIZE];
rng.fill_bytes(&mut ret);
if let Ok(key) = Self::parse(&ret) {
return key;
}
}
}
//序列化私鑰
pub fn serialize(&self) -> [u8; util::SECRET_KEY_SIZE] {
self.0.b32()
}
}
下面開始:
私鑰生成
私鑰生成首先是宣告一個陣列變數ret,它包含32個u8(即8位元)型別的陣列元素,并且全部初始化為0,然后使用一個隨機填充位元組的函式fill_bytes將32個陣列元素全部填充完,由于此時的32個u8型別的陣列元素是序列化的,由于回傳結果是一個Scalar型別的變數,因而需要經過parse函式反序列化后回傳,
pub fn random<R: Rng>(rng: &mut R) -> SecretKey {
loop {
let mut ret = [0u8; util::SECRET_KEY_SIZE];
rng.fill_bytes(&mut ret);
if let Ok(key) = Self::parse(&ret) {
return key;
}
}
}
Scalar為256位標量值,使用8個32位的陣列元素進行表示:
pub struct Scalar(pub [u32; 8]);
私鑰反序列化
私鑰反序列化需要呼叫一個set_b32函式,將序列化的陣列變數p傳入經函式set_b32反序列化,反序列化后要通過try_from函式檢驗私鑰是否為0,檢驗不為0之后反序列化成功,
pub fn parse(p: &[u8; util::SECRET_KEY_SIZE]) -> Result<SecretKey, Error> {
let mut elem = Scalar::default();
if !bool::from(elem.set_b32(p)) {
Self::try_from(elem)
} else {
Err(Error::InvalidSecretKey)
}
}
下面是反序列化函式set_b32的實作程序,實作目標是把32個u8轉化為8個u32:
/// 將大端序位元組序列轉化為一個標量,并判斷是否溢位:
#[must_use]
pub fn set_b32(&mut self, b32: &[u8; 32]) -> Choice {
self.0[0] = (b32[31] as u32)
| ((b32[30] as u32) << 8)
| ((b32[29] as u32) << 16)
| ((b32[28] as u32) << 24);
self.0[1] = (b32[27] as u32)
| ((b32[26] as u32) << 8)
| ((b32[25] as u32) << 16)
| ((b32[24] as u32) << 24);
self.0[2] = (b32[23] as u32)
| ((b32[22] as u32) << 8)
| ((b32[21] as u32) << 16)
| ((b32[20] as u32) << 24);
self.0[3] = (b32[19] as u32)
| ((b32[18] as u32) << 8)
| ((b32[17] as u32) << 16)
| ((b32[16] as u32) << 24);
self.0[4] = (b32[15] as u32)
| ((b32[14] as u32) << 8)
| ((b32[13] as u32) << 16)
| ((b32[12] as u32) << 24);
self.0[5] = (b32[11] as u32)
| ((b32[10] as u32) << 8)
| ((b32[9] as u32) << 16)
| ((b32[8] as u32) << 24);
self.0[6] = (b32[7] as u32)
| ((b32[6] as u32) << 8)
| ((b32[5] as u32) << 16)
| ((b32[4] as u32) << 24);
self.0[7] = (b32[3] as u32)
| ((b32[2] as u32) << 8)
| ((b32[1] as u32) << 16)
| ((b32[0] as u32) << 24);
let overflow = self.check_overflow();
self.reduce(overflow);
overflow
}
此外還有try_from函式檢驗私鑰是否為0:
impl TryFrom<Scalar> for SecretKey {
type Error = Error;
fn try_from(scalar: Scalar) -> Result<Self, Error> {
if scalar.is_zero() {
Err(Error::InvalidSecretKey)
} else {
Ok(Self(scalar))
}
}
}
檢驗是否為0程序很簡單,就是判斷每個陣列元素是否為0:
pub fn is_zero(&self) -> bool {
(self.0[0]
| self.0[1]
| self.0[2]
| self.0[3]
| self.0[4]
| self.0[5]
| self.0[6]
| self.0[7])
== 0
}
下面是一個復制函式,通過呼叫copy_from_slice將序列化的私鑰復制進入序列化的陣列p,在那之前判斷陣列長度length是否為32,不為32則回傳錯誤:
pub fn parse_slice(p: &[u8]) -> Result<SecretKey, Error> {
if p.len() != util::SECRET_KEY_SIZE {
return Err(Error::InvalidInputLength);
}
let mut a = [0; 32];
a.copy_from_slice(p);
Self::parse(&a)
}
私鑰序列化
私鑰的序列化就是將8個u32轉化為32個u8,這個程序呼叫b32函式實作:
pub fn serialize(&self) -> [u8; util::SECRET_KEY_SIZE] {
self.0.b32()
}
b32函式中創建了一個包含32個u8型別陣列元素的陣列變數bin,然后呼叫函式fill_b32將私鑰序列化:
/// 將一個標量轉換為位元組序列:
pub fn b32(&self) -> [u8; 32] {
let mut bin = [0u8; 32];
self.fill_b32(&mut bin);
bin
}
函式fill_b32實作程序如下所示:
///將一個標量轉換為位元組序列:
pub fn fill_b32(&self, bin: &mut [u8; 32]) {
bin[0] = (self.0[7] >> 24) as u8;
bin[1] = (self.0[7] >> 16) as u8;
bin[2] = (self.0[7] >> 8) as u8;
bin[3] = (self.0[7]) as u8;
bin[4] = (self.0[6] >> 24) as u8;
bin[5] = (self.0[6] >> 16) as u8;
bin[6] = (self.0[6] >> 8) as u8;
bin[7] = (self.0[6]) as u8;
bin[8] = (self.0[5] >> 24) as u8;
bin[9] = (self.0[5] >> 16) as u8;
bin[10] = (self.0[5] >> 8) as u8;
bin[11] = (self.0[5]) as u8;
bin[12] = (self.0[4] >> 24) as u8;
bin[13] = (self.0[4] >> 16) as u8;
bin[14] = (self.0[4] >> 8) as u8;
bin[15] = (self.0[4]) as u8;
bin[16] = (self.0[3] >> 24) as u8;
bin[17] = (self.0[3] >> 16) as u8;
bin[18] = (self.0[3] >> 8) as u8;
bin[19] = (self.0[3]) as u8;
bin[20] = (self.0[2] >> 24) as u8;
bin[21] = (self.0[2] >> 16) as u8;
bin[22] = (self.0[2] >> 8) as u8;
bin[23] = (self.0[2]) as u8;
bin[24] = (self.0[1] >> 24) as u8;
bin[25] = (self.0[1] >> 16) as u8;
bin[26] = (self.0[1] >> 8) as u8;
bin[27] = (self.0[1]) as u8;
bin[28] = (self.0[0] >> 24) as u8;
bin[29] = (self.0[0] >> 16) as u8;
bin[30] = (self.0[0] >> 8) as u8;
bin[31] = (self.0[0]) as u8;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/374888.html
標籤:區塊鏈
上一篇:鋼鐵礦石專題研究報告(合集)
