Skip to content
Closed
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ go.work.sum

# env file
.env

target
21 changes: 21 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.PHONY: static-link
static-link:
@cd link/bindgen; cargo build --release;
@cp link/bindgen/target/release/libbindgen.a link/osx.a
@rm -rf link/bindgen/target

.PHONY: static-link-linux-amd64
static-link-linux-amd64:
@cd link/bindgen; cargo build --release;
@cp link/bindgen/target/release/libbindgen.a link/linux_amd64.a
@rm -rf link/bindgen/target

.PHONY: static-link-linux-arm64
static-link-linux-arm64:
@cd link/bindgen; cargo build --release;
@cp link/bindgen/target/release/libbindgen.a link/linux_arm64.a
@rm -rf link/bindgen/target

.PHONY: test
test:
@go test -v ./...
135 changes: 19 additions & 116 deletions hash/poseidon2_goldilocks/poseidon2.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

g "github.com/elliottech/poseidon_crypto/field/goldilocks"
gFp5 "github.com/elliottech/poseidon_crypto/field/goldilocks_quintic_extension"
link "github.com/elliottech/poseidon_crypto/link"
)

type HashOut [4]g.Element
Expand All @@ -20,9 +21,20 @@ func (h HashOut) ToUint64Array() [4]uint64 {
return [4]uint64{h[0].Uint64(), h[1].Uint64(), h[2].Uint64(), h[3].Uint64()}
}

func HashToQuinticExtension(m []g.Element) gFp5.Element {
res := HashNToMNoPad(m, 5)
return gFp5.Element(res[:])
func HashToQuinticExtension(input []g.Element) gFp5.Element {
in := make([]uint64, 0, len(input))
for _, elem := range input {
in = append(in, elem.Uint64())
}

res := link.HashToQuinticExtension(in)
return gFp5.Element([5]g.Element{
g.FromUint64(res[0]),
g.FromUint64(res[1]),
g.FromUint64(res[2]),
g.FromUint64(res[3]),
g.FromUint64(res[4]),
})
}

func HashOutFromUint64Array(arr [4]uint64) HashOut {
Expand Down Expand Up @@ -66,121 +78,12 @@ func HashTwoToOne(input1, input2 HashOut) HashOut {
}

func HashNToHashNoPad(input []g.Element) HashOut {
res := HashNToMNoPad(input, 4)
return HashOut{res[0], res[1], res[2], res[3]}
}

func HashNToMNoPad(input []g.Element, numOutputs int) []g.Element {
var perm [WIDTH]g.Element
for i := 0; i < len(input); i += RATE {
for j := 0; j < RATE && i+j < len(input); j++ {
perm[j].Set(&input[i+j])
}
Permute(&perm)
}

outputs := make([]g.Element, 0, numOutputs)
for {
for i := 0; i < RATE; i++ {
outputs = append(outputs, perm[i])
if len(outputs) == numOutputs {
return outputs
}
}
Permute(&perm)
}
}

func Permute(input *[WIDTH]g.Element) {
externalLinearLayer(input)
fullRounds(input, 0)
partialRounds(input)
fullRounds(input, ROUNDS_F_HALF)
}

func fullRounds(state *[WIDTH]g.Element, start int) {
for r := start; r < start+ROUNDS_F_HALF; r++ {
addRC(state, r)
sbox(state)
externalLinearLayer(state)
}
}

func partialRounds(state *[WIDTH]g.Element) {
for r := 0; r < ROUNDS_P; r++ {
addRCI(state, r)
sboxP(0, state)
internalLinearLayer(state)
}
}

func externalLinearLayer(s *[WIDTH]g.Element) {
for i := 0; i < 3; i++ { // 4 size window
var t0, t1, t2, t3, t4, t5, t6 g.Element
t0.Add(&s[4*i], &s[4*i+1]) // s0+s1
t1.Add(&s[4*i+2], &s[4*i+3]) // s2+s3
t2.Add(&t0, &t1) // t0+t1 = s0+s1+s2+s3
t3.Add(&t2, &s[4*i+1]) // t2+s1 = s0+2s1+s2+s3
t4.Add(&t2, &s[4*i+3]) // t2+s3 = s0+s1+s2+2s3
t5.Double(&s[4*i]) // 2s0
t6.Double(&s[4*i+2]) // 2s2
s[4*i].Add(&t3, &t0)
s[4*i+1].Add(&t6, &t3)
s[4*i+2].Add(&t1, &t4)
s[4*i+3].Add(&t5, &t4)
}

sums := [4]g.Element{}
for k := 0; k < 4; k++ {
for j := 0; j < WIDTH; j += 4 {
sums[k].Add(&sums[k], &s[j+k])
}
}
for i := 0; i < WIDTH; i++ {
s[i].Add(&s[i], &sums[i%4])
}
}

func internalLinearLayer(state *[WIDTH]g.Element) {
var sum g.Element
sum.Set(&state[0])
for i := 1; i < WIDTH; i++ {
sum.Add(&sum, &state[i])
}
for i := 0; i < WIDTH; i++ {
state[i].Mul(&state[i], &MATRIX_DIAG_12_U64[i]).
Add(&state[i], &sum)
}
}

func addRC(state *[WIDTH]g.Element, externalRound int) {
for i := 0; i < WIDTH; i++ {
state[i].Add(&state[i], &EXTERNAL_CONSTANTS[externalRound][i])
in := make([]uint64, 0, len(input))
for _, elem := range input {
in = append(in, elem.Uint64())
}
}

func addRCI(state *[WIDTH]g.Element, round int) {
state[0].Add(&state[0], &INTERNAL_CONSTANTS[round])
}

func sbox(state *[WIDTH]g.Element) {
for i := range state {
sboxP(i, state)
}
}

func sboxP(index int, state *[WIDTH]g.Element) {
var tmp g.Element
tmp.Set(&state[index])

var tmpSquare g.Element
tmpSquare.Square(&tmp)

var tmpSixth g.Element
tmpSixth.Mul(&tmpSquare, &tmp)
tmpSixth.Square(&tmpSixth)

state[index].Mul(&tmpSixth, &tmp)
return HashOutFromUint64Array(link.HashNToHashNoPad(in))
}

const BlockSize = g.Bytes // BlockSize size that poseidon consumes
Expand Down
118 changes: 118 additions & 0 deletions hash/poseidon2_goldilocks/poseidon2_purego.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package poseidon2

import (
g "github.com/elliottech/poseidon_crypto/field/goldilocks"
)

func HashNToMNoPad(input []g.Element, numOutputs int) []g.Element {
var perm [WIDTH]g.Element
for i := 0; i < len(input); i += RATE {
for j := 0; j < RATE && i+j < len(input); j++ {
perm[j].Set(&input[i+j])
}
Permute(&perm)
}

outputs := make([]g.Element, 0, numOutputs)
for {
for i := 0; i < RATE; i++ {
outputs = append(outputs, perm[i])
if len(outputs) == numOutputs {
return outputs
}
}
Permute(&perm)
}
}

func Permute(input *[WIDTH]g.Element) {
externalLinearLayer(input)
fullRounds(input, 0)
partialRounds(input)
fullRounds(input, ROUNDS_F_HALF)
}

func fullRounds(state *[WIDTH]g.Element, start int) {
for r := start; r < start+ROUNDS_F_HALF; r++ {
addRC(state, r)
sbox(state)
externalLinearLayer(state)
}
}

func partialRounds(state *[WIDTH]g.Element) {
for r := 0; r < ROUNDS_P; r++ {
addRCI(state, r)
sboxP(0, state)
internalLinearLayer(state)
}
}

func externalLinearLayer(s *[WIDTH]g.Element) {
for i := 0; i < 3; i++ { // 4 size window
var t0, t1, t2, t3, t4, t5, t6 g.Element
t0.Add(&s[4*i], &s[4*i+1]) // s0+s1
t1.Add(&s[4*i+2], &s[4*i+3]) // s2+s3
t2.Add(&t0, &t1) // t0+t1 = s0+s1+s2+s3
t3.Add(&t2, &s[4*i+1]) // t2+s1 = s0+2s1+s2+s3
t4.Add(&t2, &s[4*i+3]) // t2+s3 = s0+s1+s2+2s3
t5.Double(&s[4*i]) // 2s0
t6.Double(&s[4*i+2]) // 2s2
s[4*i].Add(&t3, &t0)
s[4*i+1].Add(&t6, &t3)
s[4*i+2].Add(&t1, &t4)
s[4*i+3].Add(&t5, &t4)
}

sums := [4]g.Element{}
for k := 0; k < 4; k++ {
for j := 0; j < WIDTH; j += 4 {
sums[k].Add(&sums[k], &s[j+k])
}
}
for i := 0; i < WIDTH; i++ {
s[i].Add(&s[i], &sums[i%4])
}
}

func internalLinearLayer(state *[WIDTH]g.Element) {
var sum g.Element
sum.Set(&state[0])
for i := 1; i < WIDTH; i++ {
sum.Add(&sum, &state[i])
}
for i := 0; i < WIDTH; i++ {
state[i].Mul(&state[i], &MATRIX_DIAG_12_U64[i]).
Add(&state[i], &sum)
}
}

func addRC(state *[WIDTH]g.Element, externalRound int) {
for i := 0; i < WIDTH; i++ {
state[i].Add(&state[i], &EXTERNAL_CONSTANTS[externalRound][i])
}
}

func addRCI(state *[WIDTH]g.Element, round int) {
state[0].Add(&state[0], &INTERNAL_CONSTANTS[round])
}

func sbox(state *[WIDTH]g.Element) {
for i := range state {
sboxP(i, state)
}
}

func sboxP(index int, state *[WIDTH]g.Element) {
var tmp g.Element
tmp.Set(&state[index])

var tmpSquare g.Element
tmpSquare.Square(&tmp)

var tmpSixth g.Element
tmpSixth.Mul(&tmpSquare, &tmp)
tmpSixth.Square(&tmpSixth)

state[index].Mul(&tmpSixth, &tmp)
}
19 changes: 0 additions & 19 deletions hash/poseidon2_goldilocks/poseidon2_test.go
Original file line number Diff line number Diff line change
@@ -1,30 +1,11 @@
package poseidon2

import (
"fmt"
"testing"

g "github.com/elliottech/poseidon_crypto/field/goldilocks"
)

func TestGetNilTreeLevels(t *testing.T) {
res := []HashOut{EmptyHashOut()}
for i := 1; i < 128; i++ {
res = append(res, HashTwoToOne(res[i-1], res[i-1]))
}

fmt.Println()
for i := 0; i < len(res); i++ {
fmt.Printf("Level %d: ", i)
leBytes := res[i].ToLittleEndianBytes()
for j := 0; j < len(leBytes); j++ {
fmt.Printf("%d ", leBytes[j])
}
fmt.Println()
}
fmt.Println()
}

func TestPermute(t *testing.T) {
inp := [WIDTH]g.Element{
g.FromUint64(5417613058500526590),
Expand Down
Loading
Loading