2019-11-03 14:32:11 +00:00
// Bitcoin secp256k1 bindings
// Written in 2019 by
// Elichai Turkel
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//
//! # secp256k1 no-std test.
//! This binary is a short smallest rust code to produce a working binary *without libstd*.
2020-03-29 14:02:29 +00:00
//! This gives us 2 things:
2021-05-20 13:18:42 +00:00
//! 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.
2019-11-03 14:32:11 +00:00
//! 2. Test that we don't accidentally import libstd into `secp256k1`.
2020-03-29 14:02:29 +00:00
//!
2019-11-03 14:32:11 +00:00
//! 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).
2020-03-29 14:02:29 +00:00
//!
2019-11-03 14:32:11 +00:00
//! 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).
//! ```
2020-03-29 14:02:29 +00:00
//!
//! Notes:
2019-11-03 14:32:11 +00:00
//! * 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`.
2020-03-29 14:02:29 +00:00
//!
2019-11-03 14:32:11 +00:00
2019-10-24 17:19:00 +00:00
#![ feature(lang_items) ]
#![ feature(start) ]
#![ feature(core_intrinsics) ]
#![ feature(panic_info_message) ]
2021-05-17 12:37:36 +00:00
#![ feature(alloc_error_handler) ]
2019-10-24 17:19:00 +00:00
#![ no_std ]
extern crate libc ;
extern crate secp256k1 ;
2019-10-24 18:05:04 +00:00
extern crate serde_cbor ;
2019-10-24 17:19:00 +00:00
2021-05-17 12:37:36 +00:00
#[ 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 ;
2019-10-24 18:04:02 +00:00
use core ::fmt ::{ self , write , Write } ;
2019-10-24 17:19:00 +00:00
use core ::intrinsics ;
use core ::panic ::PanicInfo ;
2020-03-29 14:02:29 +00:00
use secp256k1 ::ecdh ::SharedSecret ;
2020-08-28 15:18:53 +00:00
use secp256k1 ::ffi ::types ::AlignedType ;
2019-10-24 18:04:02 +00:00
use secp256k1 ::rand ::{ self , RngCore } ;
use secp256k1 ::serde ::Serialize ;
2019-10-24 17:19:00 +00:00
use secp256k1 ::* ;
2019-10-24 18:05:04 +00:00
use serde_cbor ::de ;
use serde_cbor ::ser ::SliceWrite ;
use serde_cbor ::Serializer ;
2019-10-24 18:04:02 +00:00
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 ( ) ;
}
}
2019-10-24 17:19:00 +00:00
#[ start ]
fn start ( _argc : isize , _argv : * const * const u8 ) -> isize {
2020-12-21 22:00:04 +00:00
let mut buf = [ AlignedType ::zeroed ( ) ; 70_000 ] ;
2019-10-24 17:19:00 +00:00
let size = Secp256k1 ::preallocate_size ( ) ;
unsafe { libc ::printf ( " needed size: %d \n \0 " . as_ptr ( ) as _ , size ) } ;
2019-10-24 18:04:02 +00:00
let mut secp = Secp256k1 ::preallocated_new ( & mut buf ) . unwrap ( ) ;
secp . randomize ( & mut FakeRng ) ;
let secret_key = SecretKey ::new ( & mut FakeRng ) ;
2019-10-24 17:19:00 +00:00
let public_key = PublicKey ::from_secret_key ( & secp , & secret_key ) ;
let message = Message ::from_slice ( & [ 0xab ; 32 ] ) . expect ( " 32 bytes " ) ;
let sig = secp . sign ( & message , & secret_key ) ;
assert! ( secp . verify ( & message , & sig , & public_key ) . is_ok ( ) ) ;
2019-10-24 18:04:02 +00:00
2021-05-20 13:18:42 +00:00
let rec_sig = secp . sign_recoverable ( & message , & secret_key ) ;
assert! ( secp . verify ( & message , & rec_sig . to_standard ( ) , & public_key ) . is_ok ( ) ) ;
assert_eq! ( public_key , secp . recover ( & message , & rec_sig ) . unwrap ( ) ) ;
let ( rec_id , data ) = rec_sig . serialize_compact ( ) ;
let new_rec_sig = recovery ::RecoverableSignature ::from_compact ( & data , rec_id ) . unwrap ( ) ;
assert_eq! ( rec_sig , new_rec_sig ) ;
2019-10-24 18:05:04 +00:00
let mut cbor_ser = [ 0 u8 ; 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 : Signature = de ::from_mut_slice ( & mut cbor_ser [ .. size ] ) . unwrap ( ) ;
assert_eq! ( sig , new_sig ) ;
2019-11-27 22:42:15 +00:00
let _ = SharedSecret ::new ( & public_key , & secret_key ) ;
let mut x_arr = [ 0 u8 ; 32 ] ;
2020-03-01 10:42:42 +00:00
let y_arr = SharedSecret ::new_with_hash ( & public_key , & secret_key , | x , y | {
2019-11-27 22:42:15 +00:00
x_arr = x ;
y . into ( )
2020-03-01 10:42:42 +00:00
} ) ;
2019-11-27 22:42:15 +00:00
assert_ne! ( x_arr , [ 0 u8 ; 32 ] ) ;
assert_ne! ( & y_arr [ .. ] , & [ 0 u8 ; 32 ] [ .. ] ) ;
2021-05-17 12:37:36 +00:00
#[ cfg(feature = " alloc " ) ]
{
let secp_alloc = Secp256k1 ::new ( ) ;
let public_key = PublicKey ::from_secret_key ( & secp_alloc , & secret_key ) ;
let message = Message ::from_slice ( & [ 0xab ; 32 ] ) . expect ( " 32 bytes " ) ;
let sig = secp_alloc . sign ( & message , & secret_key ) ;
assert! ( secp_alloc . verify ( & message , & sig , & public_key ) . is_ok ( ) ) ;
unsafe { libc ::printf ( " Verified alloc Successfully! \n \0 " . as_ptr ( ) as _ ) } ;
}
2019-10-24 17:19:00 +00:00
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 : [ 0 u8 ; 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 {
2019-10-24 18:04:02 +00:00
fn write_str ( & mut self , s : & str ) -> Result < ( ) , fmt ::Error > {
2019-10-24 17:19:00 +00:00
let curr = self . loc ;
if curr + s . len ( ) > MAX_PRINT {
unsafe {
libc ::printf ( " overflow \n \0 " . as_ptr ( ) as _ ) ;
intrinsics ::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 ( ) . unwrap ( ) ;
let mut buf = Print ::new ( ) ;
write ( & mut buf , * msg ) . unwrap ( ) ;
buf . print ( ) ;
2020-08-28 15:18:53 +00:00
intrinsics ::abort ( )
2019-10-24 17:19:00 +00:00
}
2021-05-17 12:37:36 +00:00
#[ alloc_error_handler ]
fn alloc_error ( _layout : Layout ) -> ! {
unsafe { libc ::printf ( " alloc shi1 \n \0 " . as_ptr ( ) as _ ) } ;
intrinsics ::abort ( )
}