-
Notifications
You must be signed in to change notification settings - Fork 280
/
Copy pathmain.rs
185 lines (159 loc) · 5.62 KB
/
main.rs
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// SPDX-License-Identifier: CC0-1.0
//! # secp256k1 no-std test.
//! This binary is a short smallest rust code to produce a working binary *without libstd*.
//! This gives us 2 things:
//! 1. Test that the parts of the code that should work in a no-std enviroment actually work. Note that this is not a comprehensive list.
//! 2. Test that we don't accidentally import libstd into `secp256k1`.
//!
//! The first is tested using the following command `cargo run --release | grep -q "Verified Successfully"`.
//! (Making sure that it successfully printed that. i.e. it didn't abort before that).
//!
//! The second is tested by the fact that it compiles. if we accidentally link against libstd we should see the following error:
//! `error[E0152]: duplicate lang item found`.
//! Example:
//! ```
//! error[E0152]: duplicate lang item found: `eh_personality`.
//! --> src/main.rs:37:1
//! |
//! 37 | pub extern "C" fn rust_eh_personality() {}
//! | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//! |
//! = note: first defined in crate `panic_unwind` (which `std` depends on).
//! ```
//!
//! Notes:
//! * Requires `panic=abort` and `--release` to not depend on libunwind(which is provided usually by libstd) https://github.com/rust-lang/rust/issues/47493
//! * Requires linking with `libc` for calling `printf`.
//!
#![feature(start)]
#![feature(alloc_error_handler)]
#![no_std]
extern crate libc;
extern crate secp256k1;
extern crate serde_cbor;
#[cfg(feature = "alloc")]
extern crate alloc;
use core::alloc::Layout;
#[cfg(feature = "alloc")]
extern crate wee_alloc;
#[cfg(feature = "alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
use core::fmt::{self, Write};
use core::panic::PanicInfo;
use secp256k1::ecdh::{self, SharedSecret};
use secp256k1::ffi::types::AlignedType;
use secp256k1::rand::{self, RngCore};
use secp256k1::serde::Serialize;
use secp256k1::*;
use serde_cbor::de;
use serde_cbor::ser::SliceWrite;
use serde_cbor::Serializer;
fn abort() -> ! {
unsafe { libc::abort() }
}
struct FakeRng;
impl RngCore for FakeRng {
fn next_u32(&mut self) -> u32 {
57
}
fn next_u64(&mut self) -> u64 {
57
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
for i in dest {
*i = 57;
}
Ok(())
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
self.try_fill_bytes(dest).unwrap();
}
}
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
let mut buf = [AlignedType::zeroed(); 70_000];
let size = Secp256k1::preallocate_size();
unsafe { libc::printf("needed size: %d\n\0".as_ptr() as _, size) };
let mut secp = Secp256k1::preallocated_new(&mut buf).unwrap();
secp.randomize(&mut FakeRng);
let secret_key = SecretKey::new(&mut FakeRng);
let public_key = PublicKey::from_secret_key(&secp, &secret_key);
let message = Message::from_digest_slice(&[0xab; 32]).expect("32 bytes");
let sig = secp.sign_ecdsa(&message, &secret_key);
assert!(secp.verify_ecdsa(&sig, &message, &public_key).is_ok());
let rec_sig = secp.sign_ecdsa_recoverable(&message, &secret_key);
assert!(secp.verify_ecdsa(&rec_sig.to_standard(), &message, &public_key).is_ok());
assert_eq!(public_key, secp.recover_ecdsa(&message, &rec_sig).unwrap());
let (rec_id, data) = rec_sig.serialize_compact();
let new_rec_sig = ecdsa::RecoverableSignature::from_compact(&data, rec_id).unwrap();
assert_eq!(rec_sig, new_rec_sig);
let mut cbor_ser = [0u8; 100];
let writer = SliceWrite::new(&mut cbor_ser[..]);
let mut ser = Serializer::new(writer);
sig.serialize(&mut ser).unwrap();
let size = ser.into_inner().bytes_written();
let new_sig: ecdsa::Signature = de::from_mut_slice(&mut cbor_ser[..size]).unwrap();
assert_eq!(sig, new_sig);
let _ = SharedSecret::new(&public_key, &secret_key);
let _ = ecdh::shared_secret_point(&public_key, &secret_key);
#[cfg(feature = "alloc")]
{
let secp_alloc = Secp256k1::new();
let public_key = PublicKey::from_secret_key(&secp_alloc, &secret_key);
let message = Message::from_digest_slice(&[0xab; 32]).expect("32 bytes");
let sig = secp_alloc.sign_ecdsa(&message, &secret_key);
assert!(secp_alloc.verify_ecdsa(&sig, &message, &public_key).is_ok());
unsafe { libc::printf("Verified alloc Successfully!\n\0".as_ptr() as _) };
}
unsafe { libc::printf("Verified Successfully!\n\0".as_ptr() as _) };
0
}
const MAX_PRINT: usize = 511;
struct Print {
loc: usize,
buf: [u8; 512],
}
impl Print {
pub fn new() -> Self {
Self {
loc: 0,
buf: [0u8; 512],
}
}
pub fn print(&self) {
unsafe {
let newline = "\n";
libc::printf(self.buf.as_ptr() as _);
libc::printf(newline.as_ptr() as _);
}
}
}
impl Write for Print {
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
let curr = self.loc;
if curr + s.len() > MAX_PRINT {
unsafe {
libc::printf("overflow\n\0".as_ptr() as _);
abort();
}
}
self.loc += s.len();
self.buf[curr..self.loc].copy_from_slice(s.as_bytes());
Ok(())
}
}
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
unsafe { libc::printf("shi1\n\0".as_ptr() as _) };
let msg = info.message();
let mut buf = Print::new();
write!(&mut buf, "{}", msg).unwrap();
buf.print();
abort()
}
#[alloc_error_handler]
fn alloc_error(_layout: Layout) -> ! {
unsafe { libc::printf("alloc shi1\n\0".as_ptr() as _) };
abort()
}