Implement CHECKSIG and CHECKSIGVERIFY

Still need the multisig ops, and p2sh
This commit is contained in:
Andrew Poelstra 2014-08-10 12:58:15 -07:00
parent ecdb750148
commit e01e9ad3be
9 changed files with 328 additions and 38 deletions

View File

@ -1,18 +1,16 @@
[package]
name = "bitcoin"
version = "0.0.1"
authors = ["Andrew Poelstra <apoelstra@wpsoftware.net>"]
[[lib]]
name = "bitcoin"
path = "src/lib.rs"
[dependencies.rust-crypto]
git = "https://github.com/DaGenix/rust-crypto.git"
[dependencies.bitcoin-secp256k1-rs]
git = "https://github.com/dpc/bitcoin-secp256k1-rs.git"

View File

@ -67,7 +67,7 @@ fn bitcoin_genesis_tx() -> Transaction {
// Outputs
let mut out_script = Script::new();
out_script.push_slice(hex_bytes("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f").unwrap().as_slice());
out_script.push_opcode(opcodes::OP_CHECKSIG);
out_script.push_opcode(opcodes::all::OP_CHECKSIG);
ret.output.push(TxOut {
value: 50 * COIN_VALUE,
script_pubkey: out_script

View File

@ -643,6 +643,7 @@ pub enum OpcodeClass {
macro_rules! ordinary_opcode(
($($op:ident),*) => (
#[repr(u8)]
#[doc(hidden)]
#[deriving(Clone, PartialEq, Eq, Show)]
pub enum Opcode {
$( $op = all::$op as u8 ),*
@ -670,12 +671,9 @@ ordinary_opcode!(
OP_GREATERTHAN, OP_LESSTHANOREQUAL, OP_GREATERTHANOREQUAL,
OP_MIN, OP_MAX, OP_WITHIN,
// crypto
OP_CHECKSIG
/*
OP_RIPEMD160, OP_SHA1, OP_SHA256, OP_HASH160, OP_HASH256,
OP_CODESEPARATOR, OP_CHECKSIG, OP_CHECKSIGVERIFY,
OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY
*/
OP_CODESEPARATOR, OP_CHECKSIG, OP_CHECKSIGVERIFY
// OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY
)

View File

@ -27,11 +27,22 @@
use std::char::from_digit;
use serialize::json;
use crypto::digest::Digest;
use crypto::ripemd160::Ripemd160;
use crypto::sha1::Sha1;
use crypto::sha2::Sha256;
use secp256k1::Secp256k1;
use secp256k1::key::PublicKey;
use blockdata::opcodes;
use blockdata::opcodes::Opcode;
use allops = blockdata::opcodes::all;
use blockdata::transaction::Transaction;
use network::encodable::{ConsensusDecodable, ConsensusEncodable};
use network::serialize::{SimpleDecoder, SimpleEncoder};
use network::serialize::{SimpleDecoder, SimpleEncoder, serialize};
use util::hash::Sha256dHash;
use util::misc::find_and_remove;
use util::thinvec::ThinVec;
#[deriving(PartialEq, Show, Clone)]
@ -43,6 +54,8 @@ pub struct Script(ThinVec<u8>);
/// would help you.
#[deriving(PartialEq, Eq, Show, Clone)]
pub enum ScriptError {
/// OP_CHECKSIG was called with a bad public key
BadPublicKey,
/// An OP_ELSE happened while not in an OP_IF tree
ElseWithoutIf,
/// An OP_ENDIF happened while not in an OP_IF tree
@ -59,6 +72,8 @@ pub enum ScriptError {
NegativePick,
/// Used OP_ROLL with a negative index
NegativeRoll,
/// Tried to execute a signature operation but no transaction context was provided
NoTransaction,
/// Tried to read an array off the stack as a number when it was more than 4 bytes
NumericOverflow,
/// Some stack operation was done with an empty stack
@ -69,6 +84,39 @@ pub enum ScriptError {
VerifyFailed,
}
/// Hashtype of a transaction, encoded in the last byte of a signature,
/// specifically in the last 5 bits `byte & 31`
#[deriving(PartialEq, Eq, Show, Clone)]
pub enum SignatureHashType {
/// 0x1: Sign all outputs
SigHashAll,
/// 0x2: Sign no outputs --- anyone can choose the destination
SigHashNone,
/// 0x3: Sign the output whose index matches this input's index. If none exists,
/// sign the hash `0000000000000000000000000000000000000000000000000000000000000001`.
/// (This rule is probably an unintentional C++ism, but it's consensus so we have
/// to follow it.)
SigHashSingle,
/// ???: Anything else is a non-canonical synonym for SigHashAll, for example
/// zero appears a few times in the chain
SigHashUnknown
}
impl SignatureHashType {
/// Returns a SignatureHashType along with a boolean indicating whether
/// the `ANYONECANPAY` flag is set, read from the last byte of a signature.
fn from_signature(signature: &[u8]) -> (SignatureHashType, bool) {
let byte = signature[signature.len() - 1];
let sighash = match byte & 0x1f {
1 => SigHashAll,
2 => SigHashNone,
3 => SigHashSingle,
_ => SigHashUnknown
};
(sighash, (byte & 0x80) != 0)
}
}
/// Helper to encode an integer in script format
fn build_scriptint(n: i64) -> Vec<u8> {
let neg = n < 0;
@ -125,15 +173,16 @@ fn read_scriptint(v: &[u8]) -> Result<i64, ScriptError> {
/// else as true", except that the overflow rules don't apply.
#[inline]
fn read_scriptbool(v: &[u8]) -> bool {
v.iter().all(|&w| w == 0)
!v.iter().all(|&w| w == 0)
}
/// Helper to read a script uint
fn read_uint<'a, I:Iterator<&'a u8>>(mut iter: I, size: uint) -> Result<uint, ScriptError> {
fn read_uint<'a, I:Iterator<(uint, &'a u8)>>(mut iter: I, size: uint)
-> Result<uint, ScriptError> {
let mut ret = 0;
for _ in range(0, size) {
match iter.next() {
Some(&n) => { ret = (ret << 8) + n as uint; }
Some((_, &n)) => { ret = (ret << 8) + n as uint; }
None => { return Err(EarlyEndOfScript); }
}
}
@ -173,6 +222,7 @@ macro_rules! stack_opcode(
});
)
/// Macro to translate numerical operations into stack ones
macro_rules! num_opcode(
($stack:ident($($var:ident),*): $op:expr) => ({
$(
@ -185,6 +235,22 @@ macro_rules! num_opcode(
});
)
/// Macro to translate hashing operations into stack ones
macro_rules! hash_opcode(
($stack:ident, $hash:ident) => ({
match $stack.pop() {
None => { return Err(PopEmptyStack); }
Some(v) => {
let mut engine = $hash::new();
engine.input(v.as_slice());
let mut ret = Vec::from_elem(engine.output_bits() / 8, 0);
engine.result(ret.as_mut_slice());
$stack.push(ret);
}
}
});
)
// OP_VERIFY macro
macro_rules! op_verify (
($stack:expr) => (
@ -255,21 +321,25 @@ impl Script {
}
/// Adds an individual opcode to the script
pub fn push_opcode(&mut self, data: Opcode) {
pub fn push_opcode(&mut self, data: allops::Opcode) {
let &Script(ref mut raw) = self;
raw.push(data as u8);
}
/// Evaluate the script, modifying the stack in place
pub fn evaluate(&self, stack: &mut Vec<Vec<u8>>) -> Result<(), ScriptError> {
pub fn evaluate(&self, stack: &mut Vec<Vec<u8>>, input_context: Option<(&Transaction, uint)>)
-> Result<(), ScriptError> {
let &Script(ref raw) = self;
let secp = Secp256k1::new();
let mut iter = raw.iter();
let mut codeseparator_index = 0u;
let mut iter = raw.iter().enumerate();
let mut exec_stack = vec![true];
let mut alt_stack = vec![];
for byte in iter {
for (index, byte) in iter {
let executing = exec_stack.iter().all(|e| *e);
println!("{}, {} len {} stack {}", index, allops::Opcode::from_u8(*byte), stack.len(), stack);
// The definitions of all these categories are in opcodes.rs
match (executing, allops::Opcode::from_u8(*byte).classify()) {
// Illegal operations mean failure regardless of execution state
@ -277,7 +347,7 @@ impl Script {
// Push number
(true, opcodes::PushNum(n)) => stack.push(build_scriptint(n as i64)),
// Push data
(true, opcodes::PushBytes(n)) => stack.push(iter.take(n).map(|n| *n).collect()),
(true, opcodes::PushBytes(n)) => stack.push(iter.by_ref().take(n).map(|(_, n)| *n).collect()),
// Return operations mean failure, but only if executed
(true, opcodes::ReturnOp) => return Err(ExecutedReturn),
// If-statements take effect when not executing
@ -300,20 +370,20 @@ impl Script {
(true, opcodes::Ordinary(op)) => {
match op {
opcodes::OP_PUSHDATA1 => {
let n = try!(read_uint(iter, 1));
let read: Vec<u8> = iter.take(n as uint).map(|n| *n).collect();
let n = try!(read_uint(iter.by_ref(), 1));
let read: Vec<u8> = iter.by_ref().take(n as uint).map(|(_, n)| *n).collect();
if read.len() < n as uint { return Err(EarlyEndOfScript); }
stack.push(read);
}
opcodes::OP_PUSHDATA2 => {
let n = try!(read_uint(iter, 2));
let read: Vec<u8> = iter.take(n as uint).map(|n| *n).collect();
let n = try!(read_uint(iter.by_ref(), 2));
let read: Vec<u8> = iter.by_ref().take(n as uint).map(|(_, n)| *n).collect();
if read.len() < n as uint { return Err(EarlyEndOfScript); }
stack.push(read);
}
opcodes::OP_PUSHDATA4 => {
let n = try!(read_uint(iter, 4));
let read: Vec<u8> = iter.take(n as uint).map(|n| *n).collect();
let n = try!(read_uint(iter.by_ref(), 4));
let read: Vec<u8> = iter.by_ref().take(n as uint).map(|(_, n)| *n).collect();
if read.len() < n as uint { return Err(EarlyEndOfScript); }
stack.push(read);
}
@ -404,9 +474,10 @@ impl Script {
}
opcodes::OP_EQUAL | opcodes::OP_EQUALVERIFY => {
if stack.len() < 2 { return Err(PopEmptyStack); }
let top = stack.len();
let eq = (*stack)[top - 2] == (*stack)[top - 1];
stack.push(build_scriptint(if eq { 1 } else { 0 }));
let a = stack.pop().unwrap();
let b = stack.pop().unwrap();
println!("comparing {} to {} , eq {}", a, b, a == b)
stack.push(build_scriptint(if a == b { 1 } else { 0 }));
if op == opcodes::OP_EQUALVERIFY { op_verify!(stack); }
}
opcodes::OP_1ADD => num_opcode!(stack(a): a + 1),
@ -432,8 +503,109 @@ impl Script {
opcodes::OP_MIN => num_opcode!(stack(b, a): if a < b {a} else {b}),
opcodes::OP_MAX => num_opcode!(stack(b, a): if a > b {a} else {b}),
opcodes::OP_WITHIN => num_opcode!(stack(c, b, a): if b <= a && a < c {1} else {0}),
// TODO: crypto
opcodes::OP_CHECKSIG => {}
opcodes::OP_RIPEMD160 => hash_opcode!(stack, Ripemd160),
opcodes::OP_SHA1 => hash_opcode!(stack, Sha1),
opcodes::OP_SHA256 => hash_opcode!(stack, Sha256),
opcodes::OP_HASH160 => {
hash_opcode!(stack, Sha256);
hash_opcode!(stack, Ripemd160);
}
opcodes::OP_HASH256 => {
hash_opcode!(stack, Sha256);
hash_opcode!(stack, Sha256);
}
opcodes::OP_CODESEPARATOR => { codeseparator_index = index; }
opcodes::OP_CHECKSIG | opcodes::OP_CHECKSIGVERIFY => {
if stack.len() < 2 { return Err(PopEmptyStack); }
let pubkey = PublicKey::from_slice(stack.pop().unwrap().as_slice());
let signature = stack.pop().unwrap();
println!("pubkey {} sig {}", pubkey, signature);
if pubkey.is_err() {
stack.push(build_scriptint(0));
} else if signature.len() == 0 {
stack.push(build_scriptint(0));
} else {
// This is as far as we can go without a transaction, so fail here
if input_context.is_none() { return Err(NoTransaction); }
// Otherwise unwrap it
let (tx, input_index) = input_context.unwrap();
let pubkey = pubkey.unwrap();
let (hashtype, anyone_can_pay) =
SignatureHashType::from_signature(signature.as_slice());
// Compute the section of script that needs to be hashed: everything
// from the last CODESEPARATOR, except the signature itself.
let mut script = Vec::from_slice(raw.slice_from(codeseparator_index));
find_and_remove(&mut script, signature.as_slice());
// Compute the transaction data to be hashed
let mut tx_copy = tx.clone();
// Put the script into an Option so that we can move it (via take_unwrap())
// in the following branch/loop without the move-checker complaining about
// multiple moves.
let mut script = Some(script);
if anyone_can_pay {
// For anyone-can-pay transactions we replace the whole input array
// with just the current input, to ensure the others have no effect.
let mut old_input = tx_copy.input[input_index].clone();
old_input.script_sig = Script(ThinVec::from_vec(script.take_unwrap()));
tx_copy.input = vec![old_input];
} else {
// Otherwise we keep all the inputs, blanking out the others and even
// resetting their sequence no. if appropriate
for (n, input) in tx_copy.input.mut_iter().enumerate() {
// Zero out the scripts of other inputs
if n == input_index {
input.script_sig = Script(ThinVec::from_vec(script.take_unwrap()));
} else {
input.script_sig = Script::new();
// If we aren't signing them, also zero out the sequence number
if hashtype == SigHashSingle || hashtype == SigHashNone {
input.sequence = 0;
}
}
}
}
// Erase outputs as appropriate
let mut sighash_single_bug = false;
match hashtype {
SigHashNone => { tx_copy.output = vec![]; }
SigHashSingle => {
if input_index < tx_copy.output.len() {
let new_outs = tx_copy.output.move_iter().take(input_index + 1).collect();
tx_copy.output = new_outs;
} else {
sighash_single_bug = true;
}
}
SigHashAll | SigHashUnknown => {}
}
let signature_hash = if sighash_single_bug {
vec![1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0]
} else {
let mut data_to_sign = serialize(&tx_copy).unwrap();
data_to_sign.push(*signature.last().unwrap());
data_to_sign.push(0);
data_to_sign.push(0);
data_to_sign.push(0);
serialize(&Sha256dHash::from_data(data_to_sign.as_slice())).unwrap()
};
match secp.verify(signature_hash.as_slice(), signature.as_slice(), &pubkey) {
Ok(()) => stack.push(build_scriptint(1)),
_ => stack.push(build_scriptint(0)),
}
}
if op == opcodes::OP_CHECKSIGVERIFY { op_verify!(stack); }
}
}
}
}
@ -476,10 +648,12 @@ impl<D:SimpleDecoder<E>, E> ConsensusDecodable<D, E> for Script {
mod test {
use std::io::IoResult;
use super::{Script, build_scriptint, read_scriptint};
use super::{Script, build_scriptint, read_scriptint, read_scriptbool};
use super::{NoTransaction, PopEmptyStack, VerifyFailed};
use network::serialize::{deserialize, serialize};
use blockdata::opcodes;
use blockdata::transaction::Transaction;
use util::misc::hex_bytes;
use util::thinvec::ThinVec;
@ -507,8 +681,8 @@ mod test {
script.push_slice("NRA4VR".as_bytes()); comp.push_all([6u8, 78, 82, 65, 52, 86, 82]); assert_eq!(script, Script(comp.clone()));
// opcodes
script.push_opcode(opcodes::OP_CHECKSIG); comp.push(0xACu8); assert_eq!(script, Script(comp.clone()));
script.push_opcode(opcodes::OP_CHECKSIG); comp.push(0xACu8); assert_eq!(script, Script(comp.clone()));
script.push_opcode(opcodes::all::OP_CHECKSIG); comp.push(0xACu8); assert_eq!(script, Script(comp.clone()));
script.push_opcode(opcodes::all::OP_CHECKSIG); comp.push(0xACu8); assert_eq!(script, Script(comp.clone()));
}
#[test]
@ -534,6 +708,49 @@ mod test {
assert!(read_scriptint(build_scriptint(1 << 31).as_slice()).is_err());
assert!(read_scriptint(build_scriptint(-(1 << 31)).as_slice()).is_err());
}
#[test]
fn script_eval_simple() {
let mut script = Script::new();
assert!(script.evaluate(&mut vec![], None).is_ok());
script.push_opcode(opcodes::all::OP_RETURN);
assert!(script.evaluate(&mut vec![], None).is_err());
}
#[test]
fn script_eval_checksig_without_tx() {
let hex_pk = hex_bytes("1976a914e729dea4a3a81108e16376d1cc329c91db58999488ac").unwrap();
let script_pk: Script = deserialize(hex_pk.clone()).ok().expect("scriptpk");
// Should be able to check that the sig is there and pk correct
// before needing a transaction
assert_eq!(script_pk.evaluate(&mut vec![], None), Err(PopEmptyStack));
assert_eq!(script_pk.evaluate(&mut vec![vec![], vec![]], None), Err(VerifyFailed));
// A null signature is actually Ok -- this will just push 0 onto the stack
// since the signature is guaranteed to fail.
assert_eq!(script_pk.evaluate(&mut vec![vec![], hex_bytes("026d5d4cfef5f3d97d2263941b4d8e7aaa82910bf8e6f7c6cf1d8f0d755b9d2d1a").unwrap()], None), Ok(()));
// But if the signature is there, we need a tx to check it
assert_eq!(script_pk.evaluate(&mut vec![vec![0], hex_bytes("026d5d4cfef5f3d97d2263941b4d8e7aaa82910bf8e6f7c6cf1d8f0d755b9d2d1a").unwrap()], None), Err(NoTransaction));
}
#[test]
fn script_eval_pubkeyhash() {
// nb these are both prefixed with their length in 1 byte
let tx_hex = hex_bytes("010000000125d6681b797691aebba34b9d8e50f769ab1e8807e78405ae505c218cf8e1e9e1a20100006a47304402204c2dd8a9b6f8d425fcd8ee9a20ac73b619906a6367eac6cb93e70375225ec0160220356878eff111ff3663d7e6bf08947f94443845e0dcc54961664d922f7660b80c0121029fa8e8d8e3fd61183ab52f98d65500fd028a5d0a899c6bcd4ecaf1eda9eac284ffffffff0110270000000000001976a914299567077f41bc20059dc21a1eb1ef5a6a43b9c088ac00000000").unwrap();
let output_hex = hex_bytes("1976a914299567077f41bc20059dc21a1eb1ef5a6a43b9c088ac").unwrap();
let tx: Transaction = deserialize(tx_hex.clone()).ok().expect("transaction");
let script_pk: Script = deserialize(output_hex.clone()).ok().expect("scriptpk");
let mut stack = vec![];
assert_eq!(tx.input[0].script_sig.evaluate(&mut stack, None), Ok(()));
assert_eq!(script_pk.evaluate(&mut stack, Some((&tx, 0))), Ok(()));
assert_eq!(stack.len(), 1);
assert_eq!(read_scriptbool(stack.pop().unwrap().as_slice()), true);
println!("stack {}", stack);
}
}

View File

@ -55,6 +55,7 @@ extern crate serialize;
extern crate sync;
extern crate time;
extern crate secp256k1 = "bitcoin-secp256k1-rs";
extern crate crypto = "rust-crypto";
mod internal_macros;

View File

@ -515,7 +515,7 @@ mod tests {
assert!(failure64.is_err());
// TODO: test negative numbers
assert_eq!(deserialize(vec![0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]), Ok(0xCDABi64));
assert_eq!(deserialize(vec![0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]), Ok(0x99000099CDAB0DA0i64));
assert_eq!(deserialize(vec![0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]), Ok(-0x66ffff663254f260i64));
let failurei64: IoResult<i64> = deserialize(vec![1u8, 2, 3, 4, 5, 6, 7]);
assert!(failurei64.is_err());
}

View File

@ -230,7 +230,7 @@ impl<D:SimpleDecoder<E>, E> ConsensusDecodable<D, E> for Sha256dHash {
impl fmt::LowerHex for Sha256dHash {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let &Sha256dHash(ref data) = self;
let &Sha256dHash(data) = self;
let mut rv = [0, ..64];
let mut hex = data.iter().rev().map(|n| *n).enumerate();
for (i, ch) in hex {

View File

@ -73,11 +73,71 @@ pub fn consume_err<T>(s: &str, res: IoResult<T>) {
};
}
/// Search for `needle` in the vector `haystack` and remove every
/// instance of it, returning the number of instances removed.
pub fn find_and_remove<T:Eq+::std::fmt::Show>(haystack: &mut Vec<T>, needle: &[T]) -> uint {
if needle.len() > haystack.len() { return 0; }
let mut top = haystack.len() - needle.len();
let mut n_deleted = 0;
let mut i = 0;
while i <= top {
if haystack.slice(i, i + needle.len()) == needle {
let v = haystack.as_mut_slice();
for j in range(i, top) {
v.swap(j + needle.len(), j);
}
n_deleted += 1;
// This is ugly but prevents infinite loop in case of overflow
let overflow = top < needle.len();
top -= needle.len();
if overflow { break; }
} else {
i += 1;
}
}
haystack.truncate(top + needle.len());
n_deleted
}
#[cfg(test)]
mod tests {
use std::prelude::*;
use util::misc::hex_bytes;
use super::find_and_remove;
use super::hex_bytes;
#[test]
fn test_find_and_remove() {
let mut v = vec![1u, 2, 3, 4, 2, 3, 4, 2, 3, 4, 5, 6, 7, 8, 9];
assert_eq!(find_and_remove(&mut v, [5, 5, 5]), 0);
assert_eq!(v, vec![1, 2, 3, 4, 2, 3, 4, 2, 3, 4, 5, 6, 7, 8, 9]);
assert_eq!(find_and_remove(&mut v, [5, 6, 7]), 1);
assert_eq!(v, vec![1, 2, 3, 4, 2, 3, 4, 2, 3, 4, 8, 9]);
assert_eq!(find_and_remove(&mut v, [4, 8, 9]), 1);
assert_eq!(v, vec![1, 2, 3, 4, 2, 3, 4, 2, 3]);
assert_eq!(find_and_remove(&mut v, [1]), 1);
assert_eq!(v, vec![2, 3, 4, 2, 3, 4, 2, 3]);
assert_eq!(find_and_remove(&mut v, [2]), 3);
assert_eq!(v, vec![3, 4, 3, 4, 3]);
assert_eq!(find_and_remove(&mut v, [3, 4]), 2);
assert_eq!(v, vec![3]);
assert_eq!(find_and_remove(&mut v, [5, 5, 5]), 0);
assert_eq!(find_and_remove(&mut v, [5]), 0);
assert_eq!(find_and_remove(&mut v, [3]), 1);
assert_eq!(v, vec![]);
assert_eq!(find_and_remove(&mut v, [5, 5, 5]), 0);
assert_eq!(find_and_remove(&mut v, [5]), 0);
}
#[test]
fn test_hex_bytes() {

View File

@ -51,6 +51,16 @@ impl<T> ThinVec<T> {
}
}
/// Constructor from an ordinary vector
#[inline]
pub fn from_vec(mut v: Vec<T>) -> ThinVec<T> {
v.shrink_to_fit();
assert!(v.len() <= u32::MAX as uint);
let ret = ThinVec { ptr: v.as_mut_ptr(), cap: v.len() as u32 };
unsafe { mem::forget(v); }
ret
}
/// Iterator over elements of the vector
#[inline]
pub fn iter<'a>(&'a self) -> Items<'a, T> {
@ -87,6 +97,12 @@ impl<T> ThinVec<T> {
ptr::write(&mut *self.ptr.offset(index as int), value);
}
/// Returns a slice starting from `index`
#[inline]
pub fn slice_from<'a>(&'a self, index: uint) -> &'a [T] {
self.as_slice().slice_from(index)
}
/// Push: always reallocates, try not to use this
#[inline]
pub fn push(&mut self, value: T) {
@ -178,7 +194,7 @@ impl<T> FromIterator<T> for ThinVec<T> {
#[inline]
fn from_iter<I: Iterator<T>>(iter: I) -> ThinVec<T> {
let (lower, _) = iter.size_hint();
assert!(lower < u32::MAX as uint);
assert!(lower <= u32::MAX as uint);
unsafe {
let mut vector = ThinVec::with_capacity(lower as u32);
for (n, elem) in iter.enumerate() {