0x1::U256Implementation u256.
U256zeroonefrom_u64from_u128from_big_endianfrom_little_endianto_u128compareaddsubmuldivrempowfrom_bytesnative_addnative_subnative_mulnative_divnative_remnative_powuse 0x1::Errors;
use 0x1::Vector;
U256use vector to represent data. so that we can use buildin vector ops later to construct U256. vector should always has two elements.
struct U256 has copy, drop, store
bits: vector<u64>
invariant len(bits) == 4;
fun value_of_U256(a: U256): num {
   a.bits[0] +
   a.bits[1] * P64 +
   a.bits[2] * P64 * P64 +
   a.bits[3] * P64 * P64 * P64
}
const P32: u64 = 4294967296;
const P64: u128 = 18446744073709551616;
const EQUAL: u8 = 0;
const GREATER_THAN: u8 = 2;
const LESS_THAN: u8 = 1;
const ERR_INVALID_LENGTH: u64 = 100;
const ERR_OVERFLOW: u64 = 200;
const WORD: u8 = 4;
zeropublic fun zero(): U256::U256
onepublic fun one(): U256::U256
from_u64public fun from_u64(v: u64): U256::U256
from_u128public fun from_u128(v: u128): U256::U256
public fun from_u128(v: u128): U256 {
    let low = ((v & 0xffffffffffffffff) as u64);
    let high = ((v >> 64) as u64);
    let bits = Vector::singleton(low);
    Vector::push_back(&mut bits, high);
    Vector::push_back(&mut bits, 0u64);
    Vector::push_back(&mut bits, 0u64);
    U256 { bits }
}
pragma verify = false;
pragma opaque;
ensures value_of_U256(result) == v;
from_big_endianpublic fun from_big_endian(data: vector<u8>): U256::U256
public fun from_big_endian(data: vector<u8>): U256 {
    // TODO: define error code.
    assert!(Vector::length(&data) <= 32, Errors::invalid_argument(ERR_INVALID_LENGTH));
    from_bytes(&data, true)
}
pragma verify = false;
from_little_endianpublic fun from_little_endian(data: vector<u8>): U256::U256
public fun from_little_endian(data: vector<u8>): U256 {
    // TODO: define error code.
    assert!(Vector::length(&data) <= 32, Errors::invalid_argument(ERR_INVALID_LENGTH));
    from_bytes(&data, false)
}
pragma verify = false;
to_u128public fun to_u128(v: &U256::U256): u128
public fun to_u128(v: &U256): u128 {
    assert!(*Vector::borrow(&v.bits, 3) == 0, Errors::invalid_state(ERR_OVERFLOW));
    assert!(*Vector::borrow(&v.bits, 2) == 0, Errors::invalid_state(ERR_OVERFLOW));
    ((*Vector::borrow(&v.bits, 1) as u128) << 64) | (*Vector::borrow(&v.bits, 0) as u128)
}
pragma verify = false;
pragma opaque;
aborts_if value_of_U256(v) >= P64 * P64;
ensures value_of_U256(v) == result;
comparepublic fun compare(a: &U256::U256, b: &U256::U256): u8
public fun compare(a: &U256, b: &U256): u8 {
    let i = (WORD as u64);
    while (i > 0) {
        i = i - 1;
        let a_bits = *Vector::borrow(&a.bits, i);
        let b_bits = *Vector::borrow(&b.bits, i);
        if (a_bits != b_bits) {
            if (a_bits < b_bits) {
                return LESS_THAN
            } else {
                return GREATER_THAN
            }
        }
    };
    return EQUAL
}
addpublic fun add(a: U256::U256, b: U256::U256): U256::U256
public fun add(a: U256, b: U256): U256 {
    native_add(&mut a, &b);
    a
}
aborts_if value_of_U256(a) + value_of_U256(b) >= P64 * P64 * P64 * P64;
ensures value_of_U256(result) == value_of_U256(a) + value_of_U256(b);
subpublic fun sub(a: U256::U256, b: U256::U256): U256::U256
public fun sub(a: U256, b: U256): U256 {
    native_sub(&mut a, &b);
    a
}
aborts_if value_of_U256(a) < value_of_U256(b);
ensures value_of_U256(result) == value_of_U256(a) - value_of_U256(b);
mulpublic fun mul(a: U256::U256, b: U256::U256): U256::U256
public fun mul(a: U256, b: U256): U256 {
    native_mul(&mut a, &b);
    a
}
pragma verify = false;
pragma timeout = 200;
aborts_if value_of_U256(a) * value_of_U256(b) >= P64 * P64 * P64 * P64;
ensures value_of_U256(result) == value_of_U256(a) * value_of_U256(b);
divpublic fun div(a: U256::U256, b: U256::U256): U256::U256
public fun div(a: U256, b: U256): U256 {
    native_div(&mut a, &b);
    a
}
pragma verify = false;
pragma timeout = 160;
aborts_if value_of_U256(b) == 0;
ensures value_of_U256(result) == value_of_U256(a) / value_of_U256(b);
rempublic fun rem(a: U256::U256, b: U256::U256): U256::U256
public fun rem(a: U256, b: U256): U256 {
    native_rem(&mut a, &b);
    a
}
pragma verify = false;
pragma timeout = 160;
aborts_if value_of_U256(b) == 0;
ensures value_of_U256(result) == value_of_U256(a) % value_of_U256(b);
powpublic fun pow(a: U256::U256, b: U256::U256): U256::U256
public fun pow(a: U256, b: U256): U256 {
    native_pow(&mut a, &b);
    a
}
pragma verify = false;
pragma opaque;
pragma timeout = 600;
let p = pow_spec(value_of_U256(a), value_of_U256(b));
aborts_if p >= P64 * P64 * P64 * P64;
ensures value_of_U256(result) == p;
from_bytesfun from_bytes(data: &vector<u8>, be: bool): U256::U256
native fun from_bytes(data: &vector<u8>, be: bool): U256;
native_addfun native_add(a: &mut U256::U256, b: &U256::U256)
native fun native_add(a: &mut U256, b: &U256);
pragma opaque;
aborts_if value_of_U256(a) + value_of_U256(b) >= P64 * P64 * P64 * P64;
ensures value_of_U256(a) == value_of_U256(old(a)) + value_of_U256(b);
native_subfun native_sub(a: &mut U256::U256, b: &U256::U256)
native fun native_sub(a: &mut U256, b: &U256);
pragma opaque;
aborts_if value_of_U256(a) - value_of_U256(b) < 0;
ensures value_of_U256(a) == value_of_U256(old(a)) - value_of_U256(b);
native_mulfun native_mul(a: &mut U256::U256, b: &U256::U256)
native fun native_mul(a: &mut U256, b: &U256);
pragma opaque;
aborts_if value_of_U256(a) * value_of_U256(b) >= P64 * P64 * P64 * P64;
ensures value_of_U256(a) == value_of_U256(old(a)) * value_of_U256(b);
native_divfun native_div(a: &mut U256::U256, b: &U256::U256)
native fun native_div(a: &mut U256, b: &U256);
pragma opaque;
aborts_if value_of_U256(b) == 0;
ensures value_of_U256(a) == value_of_U256(old(a)) / value_of_U256(b);
native_remfun native_rem(a: &mut U256::U256, b: &U256::U256)
native fun native_rem(a: &mut U256, b: &U256);
pragma opaque;
aborts_if value_of_U256(b) == 0;
ensures value_of_U256(a) == value_of_U256(old(a)) % value_of_U256(b);
native_powfun native_pow(a: &mut U256::U256, b: &U256::U256)
native fun native_pow(a: &mut U256, b: &U256);
pragma opaque;
aborts_if pow_spec(value_of_U256(a), value_of_U256(b)) >= P64 * P64 * P64 * P64;
ensures value_of_U256(a) == pow_spec(value_of_U256(old(a)), value_of_U256(b));
fun pow_spec(base: num, expon: num): num {
   // This actually doesn't follow a strict definition as 0^0 is undefined
   // mathematically. But the U256::pow of Rust is defined to be like this:
   // Link: https://docs.rs/uint/0.9.3/src/uint/uint.rs.html#1000-1003
   if (expon > 0) {
       let x = pow_spec(base, expon / 2);
       if (expon % 2 == 0) { x * x } else { x * x * base }
   } else {
       1
   }
}
pragma verify = true;