From 19abe8c750ac7d1f715de8f700d3feede1572324 Mon Sep 17 00:00:00 2001 From: Miccah Date: Tue, 17 Aug 2021 01:12:39 -0500 Subject: [PATCH] math.big: add from_bytes function (#11213) --- vlib/math/big/big.v | 22 ++++++++++++++++++++++ vlib/math/big/big_test.v | 14 ++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/vlib/math/big/big.v b/vlib/math/big/big.v index a93aa9e055..7ef05349f3 100644 --- a/vlib/math/big/big.v +++ b/vlib/math/big/big.v @@ -118,6 +118,28 @@ pub fn from_string(input string) Number { return n } +// from_bytes converts an array of bytes (little-endian) to a big.Number. +// Higher precedence bytes are expected at lower indices in the array. +pub fn from_bytes(input []byte) ?Number { + if input.len > 128 { + return error('input array too large. big.Number can only hold up to 1024 bit numbers') + } + // pad input + mut padded_input := []byte{len: ((input.len + 3) & ~0x3) - input.len, cap: (input.len + 3) & ~0x3, init: 0x0} + padded_input << input + // combine every 4 bytes into a u32 and insert into n.array + mut n := Number{} + for i := 0; i < padded_input.len; i += 4 { + x3 := u32(padded_input[i]) + x2 := u32(padded_input[i + 1]) + x1 := u32(padded_input[i + 2]) + x0 := u32(padded_input[i + 3]) + val := (x3 << 24) | (x2 << 16) | (x1 << 8) | x0 + n.array[(padded_input.len - i) / 4 - 1] = val + } + return n +} + // .int() converts (a small) big.Number `n` to an ordinary integer. pub fn (n &Number) int() int { r := C.bignum_to_int(n) diff --git a/vlib/math/big/big_test.v b/vlib/math/big/big_test.v index 0742b81598..9da584542a 100644 --- a/vlib/math/big/big_test.v +++ b/vlib/math/big/big_test.v @@ -165,3 +165,17 @@ fn test_bytes_trimmed() { assert big.from_int(1024).bytes_trimmed() == [byte(0x00), 0x04] assert big.from_int(1048576).bytes_trimmed() == [byte(0x00), 0x00, 0x10] } + +fn test_from_bytes() ? { + assert big.from_bytes([]) ?.hexstr() == '0' + assert big.from_bytes([byte(0x13)]) ?.hexstr() == '13' + assert big.from_bytes([byte(0x13), 0x37]) ?.hexstr() == '1337' + assert big.from_bytes([byte(0x13), 0x37, 0xca]) ?.hexstr() == '1337ca' + assert big.from_bytes([byte(0x13), 0x37, 0xca, 0xfe]) ?.hexstr() == '1337cafe' + assert big.from_bytes([byte(0x13), 0x37, 0xca, 0xfe, 0xba]) ?.hexstr() == '1337cafeba' + assert big.from_bytes([byte(0x13), 0x37, 0xca, 0xfe, 0xba, 0xbe]) ?.hexstr() == '1337cafebabe' + assert big.from_bytes([]byte{len: 128, init: 0x0}) ?.hexstr() == '0' + if x := big.from_bytes([]byte{len: 129, init: 0x0}) { + return error('expected error, got $x') + } +}