fuel_crypto/secp256/
signature.rs1use super::{
2 backend::k1,
3 signature_format::decode_signature,
4};
5use crate::{
6 Error,
7 Message,
8 PublicKey,
9 SecretKey,
10};
11
12use fuel_types::Bytes64;
13
14use core::{
15 fmt,
16 ops::Deref,
17 str,
18};
19
20#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23#[repr(transparent)]
24pub struct Signature(Bytes64);
25
26impl Signature {
27 pub const LEN: usize = Bytes64::LEN;
29
30 pub fn from_bytes(bytes: [u8; Self::LEN]) -> Self {
35 Self(bytes.into())
36 }
37
38 pub fn from_bytes_ref(bytes: &[u8; Self::LEN]) -> &Self {
43 #[allow(unsafe_code)]
45 unsafe {
46 &*(bytes.as_ptr() as *const Self)
47 }
48 }
49
50 pub fn remove_recovery_id(&self) -> [u8; Self::LEN] {
52 let (signature, _recovery_id) = decode_signature(self.0.into());
53 signature
54 }
55
56 #[deprecated = "Use `Signature::from_bytes` instead"]
58 pub fn from_bytes_unchecked(bytes: [u8; Self::LEN]) -> Self {
59 Self::from_bytes(bytes)
60 }
61}
62
63impl Deref for Signature {
64 type Target = [u8; Signature::LEN];
65
66 fn deref(&self) -> &[u8; Signature::LEN] {
67 self.0.deref()
68 }
69}
70
71impl AsRef<[u8]> for Signature {
72 fn as_ref(&self) -> &[u8] {
73 self.0.as_ref()
74 }
75}
76
77impl AsMut<[u8]> for Signature {
78 fn as_mut(&mut self) -> &mut [u8] {
79 self.0.as_mut()
80 }
81}
82
83impl fmt::LowerHex for Signature {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 self.0.fmt(f)
86 }
87}
88
89impl fmt::UpperHex for Signature {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 self.0.fmt(f)
92 }
93}
94
95impl fmt::Debug for Signature {
96 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
97 self.0.fmt(f)
98 }
99}
100
101impl fmt::Display for Signature {
102 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
103 self.0.fmt(f)
104 }
105}
106
107impl From<Signature> for [u8; Signature::LEN] {
108 fn from(salt: Signature) -> [u8; Signature::LEN] {
109 salt.0.into()
110 }
111}
112
113impl From<Signature> for Bytes64 {
114 fn from(s: Signature) -> Self {
115 s.0
116 }
117}
118
119impl str::FromStr for Signature {
120 type Err = Error;
121
122 fn from_str(s: &str) -> Result<Self, Self::Err> {
126 Bytes64::from_str(s)
127 .map_err(|_| Error::InvalidSignature)
128 .map(|s| Self::from_bytes(s.into()))
129 }
130}
131
132impl Signature {
134 pub fn sign(secret: &SecretKey, message: &Message) -> Self {
136 Self(Bytes64::from(k1::sign(secret, message)))
137 }
138
139 pub fn recover(&self, message: &Message) -> Result<PublicKey, Error> {
141 k1::recover(*self.0, message)
142 }
143
144 pub fn verify(&self, public_key: &PublicKey, message: &Message) -> Result<(), Error> {
146 k1::verify(*self.0, **public_key, message)
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use crate::Signature;
153 use test_case::test_case;
154
155 #[test_case(0x00 => 0x00)]
156 #[test_case(0x7E => 0x7E)]
157 #[test_case(0x7F => 0x7F)]
158 #[test_case(0x80 => 0x00)]
159 #[test_case(0xFF => 0x7F)]
160 fn removes_recovery_id(s_byte: u8) -> u8 {
161 let mut sig_bytes = [0u8; 64];
162 sig_bytes[32..].fill(s_byte);
163
164 let signature = Signature::from_bytes(sig_bytes);
165 let without_recovery_id = signature.remove_recovery_id();
166 without_recovery_id[32]
167 }
168}