Browse Source

Add utils (bits)

master
arnaucube 3 years ago
parent
commit
f99bb789b9
5 changed files with 274 additions and 0 deletions
  1. +2
    -0
      go-keccak256-bits-impl/README.md
  2. +13
    -0
      go-keccak256-bits-impl/go.mod
  3. +19
    -0
      go-keccak256-bits-impl/go.sum
  4. +136
    -0
      go-keccak256-bits-impl/utils.go
  5. +104
    -0
      go-keccak256-bits-impl/utils_test.go

+ 2
- 0
go-keccak256-bits-impl/README.md

@ -0,0 +1,2 @@
# go-keccak256-bits-impl
Implementation of keccak256 hash function in Go, working with bits instead of bytes&uint64, in order to recreate the Circom circuit behaviour.

+ 13
- 0
go-keccak256-bits-impl/go.mod

@ -0,0 +1,13 @@
module keccak
go 1.17
require github.com/frankban/quicktest v1.14.0
require (
github.com/google/go-cmp v0.5.6 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.6.1 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
)

+ 19
- 0
go-keccak256-bits-impl/go.sum

@ -0,0 +1,19 @@
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss=
github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=

+ 136
- 0
go-keccak256-bits-impl/utils.go

@ -0,0 +1,136 @@
package keccak
import (
"encoding/binary"
"fmt"
"math"
)
func bytesToU64(v []byte) uint64 {
return uint64(v[0]) |
uint64(v[1])<<8 |
uint64(v[2])<<16 |
uint64(v[3])<<24 |
uint64(v[4])<<32 |
uint64(v[5])<<40 |
uint64(v[6])<<48 |
uint64(v[7])<<56
}
func u64ToBytes(x uint64) []byte {
v := make([]byte, 8)
v[0] = byte(x)
v[1] = byte(x >> 8)
v[2] = byte(x >> 16)
v[3] = byte(x >> 24)
v[4] = byte(x >> 32)
v[5] = byte(x >> 40)
v[6] = byte(x >> 48)
v[7] = byte(x >> 56)
return v
}
func bitsToU64Array(b []bool) []uint64 {
r := make([]uint64, len(b)/64)
for i := 0; i < len(b)/64; i++ {
r[i] = bitsToU64(b[i*64 : i*64+64])
}
return r
}
func u64ArrayToBits(u []uint64) []bool {
r := make([]bool, len(u)*64)
for i := 0; i < len(u); i++ {
copy(r[i*64:i*64+64], u64ToBits(u[i]))
}
return r
}
func bitsToU64(b []bool) uint64 {
if len(b) != 64 {
panic(fmt.Errorf("len(b)=%d, max=64", len(b)))
}
by := bitsToBytes(b)
return binary.LittleEndian.Uint64(by)
}
func u64ToBits(u uint64) []bool {
by := u64ToBytes(u)
return bytesToBits(by)
}
func bytesToBits(b []byte) []bool {
var bits []bool
for i := 0; i < len(b); i++ {
for j := 0; j < 8; j++ {
bits = append(bits, b[i]&(1<<j) > 0)
}
}
return bits
}
func bitsToBytes(bits []bool) []byte {
bytesLen := int(math.Ceil(float64(len(bits)) / 8))
b := make([]byte, bytesLen)
for i := 0; i < len(bits); i++ {
if bits[i] {
b[i/8] |= 1 << (i % 8)
}
}
return b
}
func leftShift(a []bool, n int) []bool {
c := make([]bool, len(a))
copy(c[n:], a[:])
// c[0] = a[0]
// for i := 1; i < len(a); i++ {
// if i < n {
// c[i] = a[i]
// } else {
// c[i] = a[i-1]
// }
// }
return c
}
func rightShift(a []bool, n int) []bool {
c := make([]bool, len(a))
copy(c[:], a[n:])
// for i := len(a) - 1 - n; i >= 0; i-- {
// c[i] = a[i+1]
// }
return c
}
// TODO add unit tests
func xorSingle(a []bool) []bool {
c := make([]bool, len(a))
for i := 0; i < len(a); i++ {
c[i] = !a[i]
}
return c
}
func xor(a, b []bool) []bool {
c := make([]bool, len(a))
for i := 0; i < len(a); i++ {
if a[i] != b[i] { // XOR
c[i] = true
}
}
return c
}
func or(a, b []bool) []bool {
c := make([]bool, len(a))
for i := 0; i < len(a); i++ {
if a[i] == false && b[i] == false { // OR
c[i] = false
} else {
c[i] = true
}
}
return c
}
func and(a, b []bool) []bool {
c := make([]bool, len(a))
for i := 0; i < len(a); i++ {
if a[i] == true && b[i] == true {
c[i] = true
}
}
return c
}

+ 104
- 0
go-keccak256-bits-impl/utils_test.go

@ -0,0 +1,104 @@
package keccak
import (
"encoding/binary"
"testing"
qt "github.com/frankban/quicktest"
)
func TestUtilsBytesToBool(t *testing.T) {
b := []byte{0, 1, 2, 3, 255, 254, 253}
bits := bytesToBits(b)
// for i := 0; i < len(b); i++ {
// fmt.Println(i*8, i*8+8, b[i], bits[i*8:i*8+8])
// }
qt.Assert(t, bits[0:8], qt.DeepEquals,
[]bool{false, false, false, false, false, false, false, false})
qt.Assert(t, bits[8:16], qt.DeepEquals,
[]bool{true, false, false, false, false, false, false, false})
qt.Assert(t, bits[16:24], qt.DeepEquals,
[]bool{false, true, false, false, false, false, false, false})
qt.Assert(t, bits[24:32], qt.DeepEquals,
[]bool{true, true, false, false, false, false, false, false})
qt.Assert(t, bits[32:40], qt.DeepEquals,
[]bool{true, true, true, true, true, true, true, true})
qt.Assert(t, bits[40:48], qt.DeepEquals,
[]bool{false, true, true, true, true, true, true, true})
qt.Assert(t, bits[48:56], qt.DeepEquals,
[]bool{true, false, true, true, true, true, true, true})
}
func TestUtilsBitsToBytes(t *testing.T) {
b := []byte{0, 1, 2, 3, 255, 254, 253}
bits := bytesToBits(b)
b2 := bitsToBytes(bits)
qt.Assert(t, b2, qt.DeepEquals, b)
}
func TestUtilsU64(t *testing.T) {
u := uint64(100)
b := make([]byte, 8)
binary.LittleEndian.PutUint64(b, u)
// toUint64
// with bytes
uRes := bytesToU64(b)
qt.Assert(t, uRes, qt.Equals, u)
// with bits
uRes = bitsToU64(bytesToBits(b))
qt.Assert(t, uRes, qt.Equals, u)
// fromUint64
// with bytes
bRes := u64ToBytes(u)
qt.Assert(t, bRes, qt.DeepEquals, b)
// with bits
bResBits := u64ToBits(u)
qt.Assert(t, bResBits, qt.DeepEquals, bytesToBits(b))
}
func TestUtilsLeftShift(t *testing.T) {
u := uint64(2)
bits := u64ToBits(u)
r := leftShift(bits, 1)
qt.Assert(t, bitsToU64(r), qt.Equals, u<<1)
u = uint64(9)
bits = u64ToBits(u)
r = leftShift(bits, 1)
qt.Assert(t, bitsToU64(r), qt.Equals, u<<1)
u = uint64(14)
bits = u64ToBits(u)
r = leftShift(bits, 63)
qt.Assert(t, bitsToU64(r), qt.Equals, u<<63)
u = uint64(123456)
bits = u64ToBits(u)
r = leftShift(bits, 1)
qt.Assert(t, bitsToU64(r), qt.Equals, u<<1)
}
func TestUtilsRightShift(t *testing.T) {
u := uint64(2)
bits := u64ToBits(u)
r := rightShift(bits, 1)
qt.Assert(t, bitsToU64(r), qt.Equals, u>>1)
u = uint64(9)
bits = u64ToBits(u)
r = rightShift(bits, 1)
qt.Assert(t, bitsToU64(r), qt.Equals, u>>1)
u = uint64(14)
bits = u64ToBits(u)
r = rightShift(bits, 63)
qt.Assert(t, bitsToU64(r), qt.Equals, u>>63)
u = uint64(123456)
bits = u64ToBits(u)
r = rightShift(bits, 1)
qt.Assert(t, bitsToU64(r), qt.Equals, u>>1)
}

Loading…
Cancel
Save