1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
use crate::bindings::{
secp256k1_ec_pubkey_create, secp256k1_ecdsa_sign, secp256k1_ecdsa_signature,
secp256k1_ecdsa_verify, secp256k1_pubkey,
};
use crate::context::Context;
use crate::scalar::Scalar;
#[derive(Debug)]
pub enum Error {
InvalidSecretKey,
}
pub struct PubKey {
key: secp256k1_pubkey,
}
impl PubKey {
pub fn new(ctx: &Context, sec_key: &Scalar) -> Result<Self, Error> {
let mut pub_key = Self {
key: secp256k1_pubkey { data: [0; 64] },
};
if unsafe {
secp256k1_ec_pubkey_create(ctx.context, &mut pub_key.key, sec_key.to_bytes().as_ptr())
} == 0
{
return Err(Error::InvalidSecretKey);
}
Ok(pub_key)
}
}
pub struct Signature {
pub signature: secp256k1_ecdsa_signature,
}
impl Signature {
pub fn new(ctx: &Context, hash: &[u8], sec_key: &Scalar) -> Result<Self, Error> {
let mut sig = Self {
signature: secp256k1_ecdsa_signature { data: [0; 64] },
};
if unsafe {
secp256k1_ecdsa_sign(
ctx.context,
&mut sig.signature,
hash.as_ptr(),
sec_key.to_bytes().as_ptr(),
None,
std::ptr::null_mut::<::std::os::raw::c_void>(),
)
} == 0
{
return Err(Error::InvalidSecretKey);
}
Ok(sig)
}
pub fn verify(self, ctx: &Context, hash: &[u8], pub_key: &PubKey) -> bool {
1 == unsafe {
secp256k1_ecdsa_verify(ctx.context, &self.signature, hash.as_ptr(), &pub_key.key)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use rand_core::OsRng;
use sha3::{Digest, Sha3_256};
#[test]
fn signature_generation() {
let ctx = Context::default();
let mut rnd = OsRng::default();
let sec_key = Scalar::random(&mut rnd);
let pub_key = PubKey::new(&ctx, &sec_key).unwrap();
let msg = b"Hello, world!";
let mut hasher = Sha3_256::new();
hasher.update(msg);
let msg_hash = hasher.finalize();
let sig = Signature::new(&ctx, &msg_hash, &sec_key).unwrap();
assert!(sig.verify(&ctx, &msg_hash, &pub_key));
}
}