v icon indicating copy to clipboard operation
v copied to clipboard

Add std go like RSA and Binary

Open emma-eva opened this issue 2 years ago • 3 comments

Describe the feature

rsa like go and binary read like go

Use Case

its important everytime

Proposed Solution

No response

Other Information

No response

Acknowledgements

  • [ ] I may be able to implement this feature request
  • [ ] This feature might incur a breaking change

Version used

recent

Environment details (OS name and version, etc.)

all

emma-eva avatar Aug 02 '23 03:08 emma-eva

Can you describe more about this feature like RSA encryption or any other language?

tusharv01 avatar Oct 06 '23 14:10 tusharv01

Can you describe more about this feature like RSA encryption or any other language?

you can check both on go repo. Binary: https://github.com/golang/go/tree/master/src/encoding/binary Rsa: https://github.com/golang/go/tree/master/src/crypto/rsa

Can be convert this binary go code to v code?

package main

import (
	"errors"
	"io"
	"math"
	"reflect"
	"sync"
	"fmt"
	"strings"
)


type ByteOrder interface {
	Uint16([]byte) uint16
	Uint32([]byte) uint32
	Uint64([]byte) uint64
}

var LittleEndian littleEndian
type littleEndian struct{}

func (littleEndian) Uint16(b []byte) uint16 {
	return uint16(b[0]) | uint16(b[1])<<8
}

func (littleEndian) Uint32(b []byte) uint32 {
	return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
}

func (littleEndian) Uint64(b []byte) uint64 {
	return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
		uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
}

func Read(r io.Reader, order ByteOrder, data interface{}) error {
	if n := intDataSize(data); n != 0 {
		bs := make([]byte, n)
		if _, err := io.ReadFull(r, bs); err != nil {
			return err
		}
		switch data := data.(type) {
		case *bool:
			*data = bs[0] != 0
		case *int8:
			*data = int8(bs[0])
		case *uint8:
			*data = bs[0]
		case *int16:
			*data = int16(order.Uint16(bs))
		case *uint16:
			*data = order.Uint16(bs)
		case *int32:
			*data = int32(order.Uint32(bs))
		case *uint32:
			*data = order.Uint32(bs)
		case *int64:
			*data = int64(order.Uint64(bs))
		case *uint64:
			*data = order.Uint64(bs)
		case *float32:
			*data = math.Float32frombits(order.Uint32(bs))
		case *float64:
			*data = math.Float64frombits(order.Uint64(bs))
		case []bool:
			for i, x := range bs {
				data[i] = x != 0
			}
		case []int8:
			for i, x := range bs {
				data[i] = int8(x)
			}
		case []uint8:
			copy(data, bs)
		case []int16:
			for i := range data {
				data[i] = int16(order.Uint16(bs[2*i:]))
			}
		case []uint16:
			for i := range data {
				data[i] = order.Uint16(bs[2*i:])
			}
		case []int32:
			for i := range data {
				data[i] = int32(order.Uint32(bs[4*i:]))
			}
		case []uint32:
			for i := range data {
				data[i] = order.Uint32(bs[4*i:])
			}
		case []int64:
			for i := range data {
				data[i] = int64(order.Uint64(bs[8*i:]))
			}
		case []uint64:
			for i := range data {
				data[i] = order.Uint64(bs[8*i:])
			}
		case []float32:
			for i := range data {
				data[i] = math.Float32frombits(order.Uint32(bs[4*i:]))
			}
		case []float64:
			for i := range data {
				data[i] = math.Float64frombits(order.Uint64(bs[8*i:]))
			}
		default:
			n = 0
		}
		if n != 0 {
			return nil
		}
	}

	v := reflect.ValueOf(data)
	size := -1
	switch v.Kind() {
		case reflect.Pointer:
			v = v.Elem()
			size = dataSize(v)
		case reflect.Slice:
			size = dataSize(v)
	}
	if size < 0 {
		return errors.New("Read: invalid type " + reflect.TypeOf(data).String())
	}
	d := &decoder{order: order, buf: make([]byte, size)}
	if _, err := io.ReadFull(r, d.buf); err != nil {
		return err
	}
	d.value(v)
	return nil
}

func Size(v interface{}) int {
	return dataSize(reflect.Indirect(reflect.ValueOf(v)))
}

var structSize sync.Map

func dataSize(v reflect.Value) int {
	switch v.Kind() {
	case reflect.Slice:
		if s := sizeof(v.Type().Elem()); s >= 0 {
			return s * v.Len()
		}
		return -1

	case reflect.Struct:
		t := v.Type()
		if size, ok := structSize.Load(t); ok {
			return size.(int)
		}
		size := sizeof(t)
		structSize.Store(t, size)
		return size

	default:
		return sizeof(v.Type())
	}
}

func sizeof(t reflect.Type) int {
	switch t.Kind() {
	case reflect.Array:
		if s := sizeof(t.Elem()); s >= 0 {
			return s * t.Len()
		}

	case reflect.Struct:
		sum := 0
		for i, n := 0, t.NumField(); i < n; i++ {
			s := sizeof(t.Field(i).Type)
			if s < 0 {
				return -1
			}
			sum += s
		}
		return sum

	case reflect.Bool,
		reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
		reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
		return int(t.Size())
	}

	return -1
}

type coder struct {
	order  ByteOrder
	buf    []byte
	offset int
}

type decoder coder

func (d *decoder) bool() bool {
	x := d.buf[d.offset]
	d.offset++
	return x != 0
}

func (d *decoder) uint8() uint8 {
	x := d.buf[d.offset]
	d.offset++
	return x
}

func (d *decoder) uint16() uint16 {
	x := d.order.Uint16(d.buf[d.offset : d.offset+2])
	d.offset += 2
	return x
}

func (d *decoder) uint32() uint32 {
	x := d.order.Uint32(d.buf[d.offset : d.offset+4])
	d.offset += 4
	return x
}

func (d *decoder) uint64() uint64 {
	x := d.order.Uint64(d.buf[d.offset : d.offset+8])
	d.offset += 8
	return x
}

func (d *decoder) int8() int8 { return int8(d.uint8()) }
func (d *decoder) int16() int16 { return int16(d.uint16()) }
func (d *decoder) int32() int32 { return int32(d.uint32()) }
func (d *decoder) int64() int64 { return int64(d.uint64()) }

func (d *decoder) value(v reflect.Value) {
	switch v.Kind() {
	case reflect.Array:
		l := v.Len()
		for i := 0; i < l; i++ {
			d.value(v.Index(i))
		}

	case reflect.Struct:
		t := v.Type()
		l := v.NumField()
		for i := 0; i < l; i++ {
			if v := v.Field(i); v.CanSet() || t.Field(i).Name != "_" {
				d.value(v)
			} else {
				d.skip(v)
			}
		}

	case reflect.Slice:
		l := v.Len()
		for i := 0; i < l; i++ {
			d.value(v.Index(i))
		}

	case reflect.Bool:
		v.SetBool(d.bool())

	case reflect.Int8:
		v.SetInt(int64(d.int8()))
	case reflect.Int16:
		v.SetInt(int64(d.int16()))
	case reflect.Int32:
		v.SetInt(int64(d.int32()))
	case reflect.Int64:
		v.SetInt(d.int64())

	case reflect.Uint8:
		v.SetUint(uint64(d.uint8()))
	case reflect.Uint16:
		v.SetUint(uint64(d.uint16()))
	case reflect.Uint32:
		v.SetUint(uint64(d.uint32()))
	case reflect.Uint64:
		v.SetUint(d.uint64())

	case reflect.Float32:
		v.SetFloat(float64(math.Float32frombits(d.uint32())))
	case reflect.Float64:
		v.SetFloat(math.Float64frombits(d.uint64()))

	case reflect.Complex64:
		v.SetComplex(complex(
			float64(math.Float32frombits(d.uint32())),
			float64(math.Float32frombits(d.uint32())),
		))
	case reflect.Complex128:
		v.SetComplex(complex(
			math.Float64frombits(d.uint64()),
			math.Float64frombits(d.uint64()),
		))
	}
}

func (d *decoder) skip(v reflect.Value) {
	d.offset += dataSize(v)
}

func intDataSize(data interface{}) int {
	switch data := data.(type) {
	case bool, int8, uint8, *bool, *int8, *uint8:
		return 1
	case []bool:
		return len(data)
	case []int8:
		return len(data)
	case []uint8:
		return len(data)
	case int16, uint16, *int16, *uint16:
		return 2
	case []int16:
		return 2 * len(data)
	case []uint16:
		return 2 * len(data)
	case int32, uint32, *int32, *uint32:
		return 4
	case []int32:
		return 4 * len(data)
	case []uint32:
		return 4 * len(data)
	case int64, uint64, *int64, *uint64:
		return 8
	case []int64:
		return 8 * len(data)
	case []uint64:
		return 8 * len(data)
	case float32, *float32:
		return 4
	case float64, *float64:
		return 8
	case []float32:
		return 4 * len(data)
	case []float64:
		return 8 * len(data)
	}
	return 0
}

func main() {
    r := strings.NewReader("\x01\x00\x00\x00\x00\x00\x00\x00")
    var data int32
    order := LittleEndian

    err := Read(r, order, &data)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println(data)
    }
}

I converted in php but can't do it in vlang:

<?php

interface ByteOrder {
    public function Uint16($b);
    public function Uint32($b);
    public function Uint64($b);
}

class littleEndian implements ByteOrder {
    public function Uint16($b) {
        return $b[0] | $b[1] << 8;
    }

    public function Uint32($b) {
        return $b[0] | $b[1] << 8 | $b[2] << 16 | $b[3] << 24;
    }

    public function Uint64($b) {
        return $b[0] | $b[1] << 8 | $b[2] << 16 | $b[3] << 24 |
            $b[4] << 32 | $b[5] << 40 | $b[6] << 48 | $b[7] << 56;
    }
}

function Read($r, $order, &$data) {
    if ($n = intDataSize($data)) {
        $bs = fread($r, $n);
        if ($bs === false) {
            return false;
        }
        switch (gettype($data)) {
            case "boolean":
                $data = $bs[0] != 0;
                break;
            case "integer":
                $data = $bs[0];
                break;
            case "float":
                $data = unpack("f", pack("V", $order->Uint32($bs)))[1];
                break;
            case "double":
                $data = unpack("d", pack("P", $order->Uint64($bs)))[1];
                break;
            case "array":
                foreach ($bs as $i => $x) {
                    $data[$i] = $x != 0;
                }
                break;
        }
        return true;
    }

    $v = $data;
    $size = -1;
    switch (gettype($v)) {
        case "array":
            $size = dataSize($v);
            break;
        case "object":
            $size = dataSize($v);
            break;
    }
    if ($size < 0) {
        return false;
    }
    $d = new decoder($order, array_fill(0, $size, 0), 0);
    if (fread($r, $d->buf) === false) {
        return false;
    }
    $d->value($v);
    return true;
}

function Size($v) {
    return dataSize($v);
}

$structSize = array();

function dataSize($v) {
    switch (gettype($v)) {
        case "array":
            if ($s = customSizeOf($v[0])) {
                return $s * count($v);
            }
            return -1;
        case "object":
            $t = get_class($v);
            global $structSize;
            if (array_key_exists($t, $structSize)) {
                return $structSize[$t];
            }
            $size = customSizeOf($t);
            $structSize[$t] = $size;
            return $size;
        default:
            return customSizeOf($v);
    }
}

function customSizeOf($t) {
    switch (gettype($t)) {
        case "array":
            if ($s = customSizeOf($t[0])) {
                return $s * count($t);
            }
            break;
        case "object":
            $sum = 0;
            foreach ($t as $field) {
                $s = customSizeOf($field);
                if ($s < 0) {
                    return -1;
                }
                $sum += $s;
            }
            return $sum;
        case "boolean":
        case "integer":
        case "double":
            return 1;
    }
    return -1;
}

class coder {
    public $order;
    public $buf;
    public $offset;

    public function __construct($order, $buf, $offset) {
        $this->order = $order;
        $this->buf = $buf;
        $this->offset = $offset;
    }
}

class decoder extends coder {
    public function bool() {
        $x = $this->buf[$this->offset];
        $this->offset++;
        return $x != 0;
    }

    public function uint8() {
        $x = $this->buf[$this->offset];
        $this->offset++;
        return $x;
    }

    public function uint16() {
        $x = $this->order->Uint16(array_slice($this->buf, $this->offset, 2));
        $this->offset += 2;
        return $x;
    }

    public function uint32() {
        $x = $this->order->Uint32(array_slice($this->buf, $this->offset, 4));
        $this->offset += 4;
        return $x;
    }

    public function uint64() {
        $x = $this->order->Uint64(array_slice($this->buf, $this->offset, 8));
        $this->offset += 8;
        return $x;
    }

    public function int8() {
        return (int)$this->uint8();
    }

    public function int16() {
        return (int)$this->uint16();
    }

    public function int32() {
        return (int)$this->uint32();
    }

    public function int64() {
        return (int)$this->uint64();
    }

    public function value(&$v) {
        switch (gettype($v)) {
            case "array":
                foreach ($v as $i => $x) {
                    $this->value($v[$i]);
                }
                break;
            case "object":
                foreach ($v as $field) {
                    if ($field->canSet() || $field->name != "_") {
                        $this->value($field);
                    } else {
                        $this->skip($field);
                    }
                }
                break;
            case "boolean":
                $v = $this->bool();
                break;
            case "integer":
                $v = $this->int32();
                break;
            case "double":
                $v = $this->float64();
                break;
        }
    }

    public function skip(&$v) {
        $this->offset += dataSize($v);
    }
}

function intDataSize($data) {
    switch (gettype($data)) {
        case "boolean":
        case "integer":
            return 1;
        case "double":
            return 8;
        case "array":
            return count($data);
    }
    return 0;
}

$r = fopen("php://memory", "r+");
fwrite($r, "\x01\x00\x00\x00\x00\x00\x00\x00");
rewind($r);
$data = 0;
$order = new littleEndian();

if (Read($r, $order, $data)) {
    echo ord($data);
} else {
    echo "Error";
}

?>

emma-eva avatar Oct 08 '23 14:10 emma-eva

There are already encoding.binary in the v modules, and rsa is considered deprecated, the stock already has support more recent alternative

blackshirt avatar Apr 12 '24 10:04 blackshirt