Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: update ton message hash dependecies #1238

Merged
merged 1 commit into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions rust/apps/ethereum/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions rust/apps/ton/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions rust/apps/ton/src/transaction.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::errors::Result;
use crate::structs::{TonProof, TonTransaction};
use crate::utils::sha256;
use crate::vendor::cell::BagOfCells;
use crate::vendor::cell::{BagOfCells, ArcCell};
use alloc::{format, vec};
use alloc::vec::Vec;
use third_party::cryptoxide::ed25519;
Expand All @@ -14,8 +14,9 @@ pub fn parse_transaction(serial: &[u8]) -> Result<TonTransaction> {
pub fn buffer_to_sign(serial: &[u8]) -> Result<Vec<u8>> {
let boc = BagOfCells::parse(serial)?;
let root = boc.single_root()?;
let buffer_to_sign = root.cell_hash()?;
Ok(buffer_to_sign)

let buffer_to_sign = root.cell_hash();
Ok(buffer_to_sign.to_vec())
}

pub fn sign_transaction(serial: &[u8], sk: [u8; 32]) -> Result<[u8; 64]> {
Expand Down
346 changes: 27 additions & 319 deletions rust/apps/ton/src/vendor/cell/bag_of_cells.rs

Large diffs are not rendered by default.

4 changes: 1 addition & 3 deletions rust/apps/ton/src/vendor/cell/bit_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,8 @@ fn create_biguint_with_ones(n: usize) -> BigUint {
mod tests {
use num_bigint::BigUint;
use num_traits::ToPrimitive;
extern crate std;
use std::println;

use crate::vendor::cell::bit_string::create_biguint_with_ones;
use crate::cell::bit_string::create_biguint_with_ones;

#[test]
fn test_create_biguint_with_ones() -> anyhow::Result<()> {
Expand Down
247 changes: 189 additions & 58 deletions rust/apps/ton/src/vendor/cell/builder.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use alloc::format;
use alloc::string::ToString;
use core::ops::Add;
use alloc::sync::Arc;

use alloc::vec::Vec;
use alloc::vec;
use alloc::format;
use bitstream_io::{BigEndian, BitWrite, BitWriter};
use num_bigint::{BigInt, BigUint};
use num_traits::Zero;
use num_bigint::{BigInt, BigUint, Sign};
use num_traits::{One, Zero};
use alloc::string::ToString;

use crate::vendor::address::TonAddress;
use crate::vendor::cell::error::{MapTonCellError, TonCellError};
Expand All @@ -17,6 +19,7 @@ const MAX_CELL_REFERENCES: usize = 4;
pub struct CellBuilder {
bit_writer: BitWriter<Vec<u8>, BigEndian>,
references: Vec<ArcCell>,
is_cell_exotic: bool,
}

impl CellBuilder {
Expand All @@ -25,9 +28,14 @@ impl CellBuilder {
CellBuilder {
bit_writer,
references: Vec::new(),
is_cell_exotic: false,
}
}

pub fn set_cell_is_exotic(&mut self, val: bool) {
self.is_cell_exotic = val;
}

pub fn store_bit(&mut self, val: bool) -> Result<&mut Self, TonCellError> {
self.bit_writer.write_bit(val).map_cell_builder_error()?;
Ok(self)
Expand Down Expand Up @@ -78,68 +86,64 @@ impl CellBuilder {
pub fn store_uint(&mut self, bit_len: usize, val: &BigUint) -> Result<&mut Self, TonCellError> {
if val.bits() as usize > bit_len {
return Err(TonCellError::cell_builder_error(format!(
"Value {} doesn't fit in {} bits",
val, bit_len
"Value {} doesn't fit in {} bits (takes {} bits)",
val,
bit_len,
val.bits()
)));
}
let bytes = val.to_bytes_be();
let num_full_bytes = bit_len / 8;
let num_bits_in_high_byte = bit_len % 8;
if bytes.len() > num_full_bytes + 1 {
return Err(TonCellError::cell_builder_error(format!(
"Internal error: can't fit {} into {} bits ",
val, bit_len
)));
// example: bit_len=13, val=5. 5 = 00000101, we must store 0000000000101
// leading_zeros_bits = 10
// leading_zeros_bytes = 10 / 8 = 1
let leading_zero_bits = bit_len - val.bits() as usize;
let leading_zeros_bytes = leading_zero_bits / 8;
for _ in 0..leading_zeros_bytes {
self.store_byte(0)?;
}
if num_bits_in_high_byte > 0 {
let high_byte: u8 = if bytes.len() == num_full_bytes + 1 {
bytes[0]
} else {
0
};
self.store_u8(num_bits_in_high_byte, high_byte)?;
// we must align high byte of val to specified bit_len, 00101 in our case
let extra_zeros = leading_zero_bits % 8;
for _ in 0..extra_zeros {
self.store_bit(false)?;
}
let num_empty_bytes = num_full_bytes - bytes.len();
for _ in 0..num_empty_bytes {
self.store_byte(0)?;
// and then store val's high byte in minimum number of bits
let val_bytes = val.to_bytes_be();
let high_bits_cnt = {
let cnt = val.bits() % 8;
if cnt == 0 {
8
} else {
cnt
}
};
let high_byte = val_bytes[0];
for i in 0..high_bits_cnt {
self.store_bit(high_byte & (1 << (high_bits_cnt - i - 1)) != 0)?;
}
for b in bytes {
self.store_byte(b)?;
// store the rest of val
for byte in val_bytes.iter().skip(1) {
self.store_byte(*byte)?;
}
Ok(self)
}

pub fn store_int(&mut self, bit_len: usize, val: &BigInt) -> Result<&mut Self, TonCellError> {
if val.bits() as usize > bit_len {
let (sign, mag) = val.clone().into_parts();
let bit_len = bit_len - 1; // reserve 1 bit for sign
if bit_len < mag.bits() as usize {
return Err(TonCellError::cell_builder_error(format!(
"Value {} doesn't fit in {} bits",
val, bit_len
)));
}
let bytes = val.to_signed_bytes_be();
let num_full_bytes = bit_len / 8;
let num_bits_in_high_byte = bit_len % 8;
if bytes.len() > num_full_bytes + 1 {
return Err(TonCellError::cell_builder_error(format!(
"Internal error: can't fit {} into {} bits ",
val, bit_len
"Value {} doesn't fit in {} bits (takes {} bits)",
val,
bit_len,
mag.bits()
)));
}
if num_bits_in_high_byte > 0 {
let high_byte: u8 = if bytes.len() == num_full_bytes + 1 {
bytes[0]
} else {
0
};
self.store_u8(num_bits_in_high_byte, high_byte)?;
}
let num_empty_bytes = num_full_bytes - bytes.len();
for _ in 0..num_empty_bytes {
if sign == Sign::Minus {
self.store_byte(1)?;
self.store_uint(bit_len, &extend_and_invert_bits(bit_len, &mag)?)?;
} else {
self.store_byte(0)?;
}
for b in bytes {
self.store_byte(b)?;
}
self.store_uint(bit_len, &mag)?;
};
Ok(self)
}

Expand Down Expand Up @@ -275,11 +279,13 @@ impl CellBuilder {
ref_count
)));
}
Ok(Cell {
data: vec.clone(),

Cell::new(
vec.clone(),
bit_len,
references: self.references.clone(),
})
self.references.clone(),
self.is_cell_exotic,
)
} else {
Err(TonCellError::CellBuilderError(
"Stream is not byte-aligned".to_string(),
Expand All @@ -288,6 +294,30 @@ impl CellBuilder {
}
}

fn extend_and_invert_bits(bits_cnt: usize, src: &BigUint) -> Result<BigUint, TonCellError> {
if bits_cnt < src.bits() as usize {
return Err(TonCellError::cell_builder_error(format!(
"Can't invert bits: value {} doesn't fit in {} bits",
src, bits_cnt
)));
}

let src_bytes = src.to_bytes_be();
let inverted_bytes_cnt = (bits_cnt + 7) / 8;
let mut inverted = vec![0xffu8; inverted_bytes_cnt];
// can be optimized
for (pos, byte) in src_bytes.iter().rev().enumerate() {
let inverted_pos = inverted.len() - 1 - pos;
inverted[inverted_pos] ^= byte;
}
let mut inverted_val_bytes = BigUint::from_bytes_be(&inverted)
.add(BigUint::one())
.to_bytes_be();
let leading_zeros = inverted_bytes_cnt * 8 - bits_cnt;
inverted_val_bytes[0] &= 0xffu8 >> leading_zeros;
Ok(BigUint::from_bytes_be(&inverted_val_bytes))
}

impl Default for CellBuilder {
fn default() -> Self {
Self::new()
Expand All @@ -296,8 +326,38 @@ impl Default for CellBuilder {

#[cfg(test)]
mod tests {
use crate::vendor::address::TonAddress;
use crate::vendor::cell::CellBuilder;
use std::str::FromStr;

use num_bigint::{BigInt, BigUint, Sign};
use tokio_test::{assert_err, assert_ok};

use crate::address::TonAddress;
use crate::cell::builder::extend_and_invert_bits;
use crate::cell::CellBuilder;

#[test]
fn test_extend_and_invert_bits() -> anyhow::Result<()> {
let a = BigUint::from(1u8);
let b = extend_and_invert_bits(8, &a)?;
println!("a: {:0x}", a);
println!("b: {:0x}", b);
assert_eq!(b, BigUint::from(0xffu8));

let b = extend_and_invert_bits(16, &a)?;
assert_eq!(b, BigUint::from_slice(&[0xffffu32]));

let b = extend_and_invert_bits(20, &a)?;
assert_eq!(b, BigUint::from_slice(&[0xfffffu32]));

let b = extend_and_invert_bits(8, &a)?;
assert_eq!(b, BigUint::from_slice(&[0xffu32]));

let b = extend_and_invert_bits(9, &a)?;
assert_eq!(b, BigUint::from_slice(&[0x1ffu32]));

assert_err!(extend_and_invert_bits(3, &BigUint::from(10u32)));
Ok(())
}

#[test]
fn write_bit() -> anyhow::Result<()> {
Expand Down Expand Up @@ -399,4 +459,75 @@ mod tests {
assert_eq!(result, addr);
Ok(())
}

#[test]
fn write_big_int() -> anyhow::Result<()> {
let value = BigInt::from_str("3")?;
let mut writer = CellBuilder::new();
assert_ok!(writer.store_int(33, &value));
let cell = writer.build()?;
println!("cell: {:?}", cell);
let written = BigInt::from_bytes_be(Sign::Plus, &cell.data);
assert_eq!(written, value);

// 256 bits (+ sign)
let value = BigInt::from_str(
"97887266651548624282413032824435501549503168134499591480902563623927645013201",
)?;
let mut writer = CellBuilder::new();
assert_ok!(writer.store_int(257, &value));
let cell = writer.build()?;
println!("cell: {:?}", cell);
let written = BigInt::from_bytes_be(Sign::Plus, &cell.data);
assert_eq!(written, value);

let value = BigInt::from_str("-5")?;
let mut writer = CellBuilder::new();
assert_ok!(writer.store_int(5, &value));
let cell = writer.build()?;
println!("cell: {:?}", cell);
let written = BigInt::from_bytes_be(Sign::Plus, &cell.data[1..]);
let expected = BigInt::from_bytes_be(Sign::Plus, &[0xB0u8]);
assert_eq!(written, expected);
Ok(())
}

#[test]
fn write_load_big_uint() -> anyhow::Result<()> {
let value = BigUint::from_str("3")?;
let mut writer = CellBuilder::new();
assert!(writer.store_uint(1, &value).is_err());
let bits_for_tests = [256, 128, 64, 8];

for bits_num in bits_for_tests.iter() {
assert_ok!(writer.store_uint(*bits_num, &value));
}
let cell = writer.build()?;
println!("cell: {:?}", cell);
let mut cell_parser = cell.parser();
for bits_num in bits_for_tests.iter() {
let written_value = assert_ok!(cell_parser.load_uint(*bits_num));
assert_eq!(written_value, value);
}

// 256 bit
let value = BigUint::from_str(
"97887266651548624282413032824435501549503168134499591480902563623927645013201",
)?;
let mut writer = CellBuilder::new();
assert!(writer.store_uint(255, &value).is_err());
let bits_for_tests = [496, 264, 256];
for bits_num in bits_for_tests.iter() {
assert_ok!(writer.store_uint(*bits_num, &value));
}
let cell = writer.build()?;
let mut cell_parser = cell.parser();
println!("cell: {:?}", cell);
for bits_num in bits_for_tests.iter() {
let written_value = assert_ok!(cell_parser.load_uint(*bits_num));
assert_eq!(written_value, value);
}

Ok(())
}
}
Loading
Loading