diff --git a/ecc/bls12-377/fr/mimc/decompose.go b/ecc/bls12-377/fr/mimc/decompose.go new file mode 100644 index 0000000000..a51138765e --- /dev/null +++ b/ecc/bls12-377/fr/mimc/decompose.go @@ -0,0 +1,46 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package mimc + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" +) + +// Decompose interpret rawBytes as a bigInt x in big endian, +// and returns the digits of x (from LSB to MSB) when x is written +// in basis modulo. +func Decompose(rawBytes []byte) []fr.Element { + + rawBigInt := big.NewInt(0).SetBytes(rawBytes) + modulo := fr.Modulus() + + // maximum number of chunks that a function + maxNbChunks := len(rawBytes) / fr.Bytes + + res := make([]fr.Element, 0, maxNbChunks) + var tmp fr.Element + t := new(big.Int) + for rawBigInt.Sign() != 0 { + rawBigInt.DivMod(rawBigInt, modulo, t) + tmp.SetBigInt(t) + res = append(res, tmp) + } + + return res +} diff --git a/ecc/bls12-377/fr/mimc/decompose_test.go b/ecc/bls12-377/fr/mimc/decompose_test.go new file mode 100644 index 0000000000..937192cedf --- /dev/null +++ b/ecc/bls12-377/fr/mimc/decompose_test.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package mimc + +import ( + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" +) + +func TestDecompose(t *testing.T) { + + // create 10 random digits in basis r + nbDigits := 10 + a := make([]fr.Element, nbDigits) + for i := 0; i < nbDigits; i++ { + a[i].SetRandom() + } + + // create a big int whose digits in basis r are a + m := fr.Modulus() + var b, tmp big.Int + for i := nbDigits - 1; i >= 0; i-- { + b.Mul(&b, m) + a[i].ToBigIntRegular(&tmp) + b.Add(&b, &tmp) + } + + // query the decomposition and compare to a + bb := b.Bytes() + d := Decompose(bb) + for i := 0; i < nbDigits; i++ { + if !d[i].Equal(&a[i]) { + t.Fatal("error decomposition") + } + } + +} diff --git a/ecc/bls12-377/fr/mimc/mimc.go b/ecc/bls12-377/fr/mimc/mimc.go index 2fd03ea0c1..0ce9f4ec0b 100644 --- a/ecc/bls12-377/fr/mimc/mimc.go +++ b/ecc/bls12-377/fr/mimc/mimc.go @@ -17,6 +17,7 @@ package mimc import ( + "errors" "hash" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" @@ -91,44 +92,44 @@ func (d *digest) BlockSize() int { } // Write (via the embedded io.Writer interface) adds more data to the running hash. -// It never returns an error. +// +// Each []byte block of size BlockSize represents a big endian fr.Element. +// +// If len(p) is not a multiple of BlockSize and any of the []byte in p represent an integer +// larger than fr.Modulus, this function returns an error. +// +// To hash arbitrary data ([]byte not representing canonical field elements) use Decompose +// function in this package. func (d *digest) Write(p []byte) (n int, err error) { n = len(p) + if n%BlockSize != 0 { + return 0, errors.New("invalid input length: must represent a list of field elements, expects a []byte of len m*BlockSize") + } + + // ensure each block represents a field element in canonical reduced form + for i := 0; i < n; i += BlockSize { + if _, err = fr.BigEndian.Element((*[BlockSize]byte)(p[i : i+BlockSize])); err != nil { + return 0, err + } + } + d.data = append(d.data, p...) return } -// Hash hash using Miyaguchi–Preneel: +// Hash hash using Miyaguchi-Preneel: // https://en.wikipedia.org/wiki/One-way_compression_function // The XOR operation is replaced by field addition, data is in Montgomery form func (d *digest) checksum() fr.Element { + // Write guarantees len(data) % BlockSize == 0 - var buffer [BlockSize]byte - var x fr.Element - - // if data size is not multiple of BlockSizes we padd: - // .. || 0xaf8 -> .. || 0x0000...0af8 - if len(d.data)%BlockSize != 0 { - q := len(d.data) / BlockSize - r := len(d.data) % BlockSize - sliceq := make([]byte, q*BlockSize) - copy(sliceq, d.data) - slicer := make([]byte, r) - copy(slicer, d.data[q*BlockSize:]) - sliceremainder := make([]byte, BlockSize-r) - d.data = append(sliceq, sliceremainder...) - d.data = append(d.data, slicer...) - } - + // TODO @ThomasPiellard shouldn't Sum() returns an error if there is no data? if len(d.data) == 0 { - d.data = make([]byte, 32) + d.data = make([]byte, BlockSize) } - nbChunks := len(d.data) / BlockSize - - for i := 0; i < nbChunks; i++ { - copy(buffer[:], d.data[i*BlockSize:(i+1)*BlockSize]) - x.SetBytes(buffer[:]) + for i := 0; i < len(d.data); i += BlockSize { + x, _ := fr.BigEndian.Element((*[BlockSize]byte)(d.data[i : i+BlockSize])) r := d.encrypt(x) d.h.Add(&r, &d.h).Add(&d.h, &x) } diff --git a/ecc/bls12-377/twistededwards/eddsa/eddsa_test.go b/ecc/bls12-377/twistededwards/eddsa/eddsa_test.go index aaf4b94cf7..1175d7458a 100644 --- a/ecc/bls12-377/twistededwards/eddsa/eddsa_test.go +++ b/ecc/bls12-377/twistededwards/eddsa/eddsa_test.go @@ -37,8 +37,10 @@ func Example() { privateKey, _ := GenerateKey(crand.Reader) publicKey := privateKey.PublicKey - // note that the message is on 4 bytes - msg := []byte{0xde, 0xad, 0xf0, 0x0d} + // generate a message (the size must be a multiple of the size of Fr) + var _msg fr.Element + _msg.SetRandom() + msg := _msg.Marshal() // sign the message signature, _ := privateKey.Sign(msg, hFunc) diff --git a/ecc/bls12-378/fr/mimc/decompose.go b/ecc/bls12-378/fr/mimc/decompose.go new file mode 100644 index 0000000000..50a124f541 --- /dev/null +++ b/ecc/bls12-378/fr/mimc/decompose.go @@ -0,0 +1,46 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package mimc + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bls12-378/fr" +) + +// Decompose interpret rawBytes as a bigInt x in big endian, +// and returns the digits of x (from LSB to MSB) when x is written +// in basis modulo. +func Decompose(rawBytes []byte) []fr.Element { + + rawBigInt := big.NewInt(0).SetBytes(rawBytes) + modulo := fr.Modulus() + + // maximum number of chunks that a function + maxNbChunks := len(rawBytes) / fr.Bytes + + res := make([]fr.Element, 0, maxNbChunks) + var tmp fr.Element + t := new(big.Int) + for rawBigInt.Sign() != 0 { + rawBigInt.DivMod(rawBigInt, modulo, t) + tmp.SetBigInt(t) + res = append(res, tmp) + } + + return res +} diff --git a/ecc/bls12-378/fr/mimc/decompose_test.go b/ecc/bls12-378/fr/mimc/decompose_test.go new file mode 100644 index 0000000000..a63b57ff51 --- /dev/null +++ b/ecc/bls12-378/fr/mimc/decompose_test.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package mimc + +import ( + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bls12-378/fr" +) + +func TestDecompose(t *testing.T) { + + // create 10 random digits in basis r + nbDigits := 10 + a := make([]fr.Element, nbDigits) + for i := 0; i < nbDigits; i++ { + a[i].SetRandom() + } + + // create a big int whose digits in basis r are a + m := fr.Modulus() + var b, tmp big.Int + for i := nbDigits - 1; i >= 0; i-- { + b.Mul(&b, m) + a[i].ToBigIntRegular(&tmp) + b.Add(&b, &tmp) + } + + // query the decomposition and compare to a + bb := b.Bytes() + d := Decompose(bb) + for i := 0; i < nbDigits; i++ { + if !d[i].Equal(&a[i]) { + t.Fatal("error decomposition") + } + } + +} diff --git a/ecc/bls12-378/fr/mimc/mimc.go b/ecc/bls12-378/fr/mimc/mimc.go index 7d788e8f42..e20b5ee79c 100644 --- a/ecc/bls12-378/fr/mimc/mimc.go +++ b/ecc/bls12-378/fr/mimc/mimc.go @@ -17,6 +17,7 @@ package mimc import ( + "errors" "hash" "github.com/consensys/gnark-crypto/ecc/bls12-378/fr" @@ -91,44 +92,44 @@ func (d *digest) BlockSize() int { } // Write (via the embedded io.Writer interface) adds more data to the running hash. -// It never returns an error. +// +// Each []byte block of size BlockSize represents a big endian fr.Element. +// +// If len(p) is not a multiple of BlockSize and any of the []byte in p represent an integer +// larger than fr.Modulus, this function returns an error. +// +// To hash arbitrary data ([]byte not representing canonical field elements) use Decompose +// function in this package. func (d *digest) Write(p []byte) (n int, err error) { n = len(p) + if n%BlockSize != 0 { + return 0, errors.New("invalid input length: must represent a list of field elements, expects a []byte of len m*BlockSize") + } + + // ensure each block represents a field element in canonical reduced form + for i := 0; i < n; i += BlockSize { + if _, err = fr.BigEndian.Element((*[BlockSize]byte)(p[i : i+BlockSize])); err != nil { + return 0, err + } + } + d.data = append(d.data, p...) return } -// Hash hash using Miyaguchi–Preneel: +// Hash hash using Miyaguchi-Preneel: // https://en.wikipedia.org/wiki/One-way_compression_function // The XOR operation is replaced by field addition, data is in Montgomery form func (d *digest) checksum() fr.Element { + // Write guarantees len(data) % BlockSize == 0 - var buffer [BlockSize]byte - var x fr.Element - - // if data size is not multiple of BlockSizes we padd: - // .. || 0xaf8 -> .. || 0x0000...0af8 - if len(d.data)%BlockSize != 0 { - q := len(d.data) / BlockSize - r := len(d.data) % BlockSize - sliceq := make([]byte, q*BlockSize) - copy(sliceq, d.data) - slicer := make([]byte, r) - copy(slicer, d.data[q*BlockSize:]) - sliceremainder := make([]byte, BlockSize-r) - d.data = append(sliceq, sliceremainder...) - d.data = append(d.data, slicer...) - } - + // TODO @ThomasPiellard shouldn't Sum() returns an error if there is no data? if len(d.data) == 0 { - d.data = make([]byte, 32) + d.data = make([]byte, BlockSize) } - nbChunks := len(d.data) / BlockSize - - for i := 0; i < nbChunks; i++ { - copy(buffer[:], d.data[i*BlockSize:(i+1)*BlockSize]) - x.SetBytes(buffer[:]) + for i := 0; i < len(d.data); i += BlockSize { + x, _ := fr.BigEndian.Element((*[BlockSize]byte)(d.data[i : i+BlockSize])) r := d.encrypt(x) d.h.Add(&r, &d.h).Add(&d.h, &x) } diff --git a/ecc/bls12-378/twistededwards/eddsa/eddsa_test.go b/ecc/bls12-378/twistededwards/eddsa/eddsa_test.go index 5cfc0927f2..f7e0956696 100644 --- a/ecc/bls12-378/twistededwards/eddsa/eddsa_test.go +++ b/ecc/bls12-378/twistededwards/eddsa/eddsa_test.go @@ -37,8 +37,10 @@ func Example() { privateKey, _ := GenerateKey(crand.Reader) publicKey := privateKey.PublicKey - // note that the message is on 4 bytes - msg := []byte{0xde, 0xad, 0xf0, 0x0d} + // generate a message (the size must be a multiple of the size of Fr) + var _msg fr.Element + _msg.SetRandom() + msg := _msg.Marshal() // sign the message signature, _ := privateKey.Sign(msg, hFunc) diff --git a/ecc/bls12-381/bandersnatch/eddsa/eddsa_test.go b/ecc/bls12-381/bandersnatch/eddsa/eddsa_test.go index 967aac1db9..85bd27ca02 100644 --- a/ecc/bls12-381/bandersnatch/eddsa/eddsa_test.go +++ b/ecc/bls12-381/bandersnatch/eddsa/eddsa_test.go @@ -37,8 +37,10 @@ func Example() { privateKey, _ := GenerateKey(crand.Reader) publicKey := privateKey.PublicKey - // note that the message is on 4 bytes - msg := []byte{0xde, 0xad, 0xf0, 0x0d} + // generate a message (the size must be a multiple of the size of Fr) + var _msg fr.Element + _msg.SetRandom() + msg := _msg.Marshal() // sign the message signature, _ := privateKey.Sign(msg, hFunc) diff --git a/ecc/bls12-381/fr/mimc/decompose.go b/ecc/bls12-381/fr/mimc/decompose.go new file mode 100644 index 0000000000..925d679327 --- /dev/null +++ b/ecc/bls12-381/fr/mimc/decompose.go @@ -0,0 +1,46 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package mimc + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" +) + +// Decompose interpret rawBytes as a bigInt x in big endian, +// and returns the digits of x (from LSB to MSB) when x is written +// in basis modulo. +func Decompose(rawBytes []byte) []fr.Element { + + rawBigInt := big.NewInt(0).SetBytes(rawBytes) + modulo := fr.Modulus() + + // maximum number of chunks that a function + maxNbChunks := len(rawBytes) / fr.Bytes + + res := make([]fr.Element, 0, maxNbChunks) + var tmp fr.Element + t := new(big.Int) + for rawBigInt.Sign() != 0 { + rawBigInt.DivMod(rawBigInt, modulo, t) + tmp.SetBigInt(t) + res = append(res, tmp) + } + + return res +} diff --git a/ecc/bls12-381/fr/mimc/decompose_test.go b/ecc/bls12-381/fr/mimc/decompose_test.go new file mode 100644 index 0000000000..36809a2aa9 --- /dev/null +++ b/ecc/bls12-381/fr/mimc/decompose_test.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package mimc + +import ( + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" +) + +func TestDecompose(t *testing.T) { + + // create 10 random digits in basis r + nbDigits := 10 + a := make([]fr.Element, nbDigits) + for i := 0; i < nbDigits; i++ { + a[i].SetRandom() + } + + // create a big int whose digits in basis r are a + m := fr.Modulus() + var b, tmp big.Int + for i := nbDigits - 1; i >= 0; i-- { + b.Mul(&b, m) + a[i].ToBigIntRegular(&tmp) + b.Add(&b, &tmp) + } + + // query the decomposition and compare to a + bb := b.Bytes() + d := Decompose(bb) + for i := 0; i < nbDigits; i++ { + if !d[i].Equal(&a[i]) { + t.Fatal("error decomposition") + } + } + +} diff --git a/ecc/bls12-381/fr/mimc/mimc.go b/ecc/bls12-381/fr/mimc/mimc.go index 89287dd062..e704e01f7a 100644 --- a/ecc/bls12-381/fr/mimc/mimc.go +++ b/ecc/bls12-381/fr/mimc/mimc.go @@ -17,6 +17,7 @@ package mimc import ( + "errors" "hash" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" @@ -91,44 +92,44 @@ func (d *digest) BlockSize() int { } // Write (via the embedded io.Writer interface) adds more data to the running hash. -// It never returns an error. +// +// Each []byte block of size BlockSize represents a big endian fr.Element. +// +// If len(p) is not a multiple of BlockSize and any of the []byte in p represent an integer +// larger than fr.Modulus, this function returns an error. +// +// To hash arbitrary data ([]byte not representing canonical field elements) use Decompose +// function in this package. func (d *digest) Write(p []byte) (n int, err error) { n = len(p) + if n%BlockSize != 0 { + return 0, errors.New("invalid input length: must represent a list of field elements, expects a []byte of len m*BlockSize") + } + + // ensure each block represents a field element in canonical reduced form + for i := 0; i < n; i += BlockSize { + if _, err = fr.BigEndian.Element((*[BlockSize]byte)(p[i : i+BlockSize])); err != nil { + return 0, err + } + } + d.data = append(d.data, p...) return } -// Hash hash using Miyaguchi–Preneel: +// Hash hash using Miyaguchi-Preneel: // https://en.wikipedia.org/wiki/One-way_compression_function // The XOR operation is replaced by field addition, data is in Montgomery form func (d *digest) checksum() fr.Element { + // Write guarantees len(data) % BlockSize == 0 - var buffer [BlockSize]byte - var x fr.Element - - // if data size is not multiple of BlockSizes we padd: - // .. || 0xaf8 -> .. || 0x0000...0af8 - if len(d.data)%BlockSize != 0 { - q := len(d.data) / BlockSize - r := len(d.data) % BlockSize - sliceq := make([]byte, q*BlockSize) - copy(sliceq, d.data) - slicer := make([]byte, r) - copy(slicer, d.data[q*BlockSize:]) - sliceremainder := make([]byte, BlockSize-r) - d.data = append(sliceq, sliceremainder...) - d.data = append(d.data, slicer...) - } - + // TODO @ThomasPiellard shouldn't Sum() returns an error if there is no data? if len(d.data) == 0 { - d.data = make([]byte, 32) + d.data = make([]byte, BlockSize) } - nbChunks := len(d.data) / BlockSize - - for i := 0; i < nbChunks; i++ { - copy(buffer[:], d.data[i*BlockSize:(i+1)*BlockSize]) - x.SetBytes(buffer[:]) + for i := 0; i < len(d.data); i += BlockSize { + x, _ := fr.BigEndian.Element((*[BlockSize]byte)(d.data[i : i+BlockSize])) r := d.encrypt(x) d.h.Add(&r, &d.h).Add(&d.h, &x) } diff --git a/ecc/bls12-381/twistededwards/eddsa/eddsa_test.go b/ecc/bls12-381/twistededwards/eddsa/eddsa_test.go index 967aac1db9..85bd27ca02 100644 --- a/ecc/bls12-381/twistededwards/eddsa/eddsa_test.go +++ b/ecc/bls12-381/twistededwards/eddsa/eddsa_test.go @@ -37,8 +37,10 @@ func Example() { privateKey, _ := GenerateKey(crand.Reader) publicKey := privateKey.PublicKey - // note that the message is on 4 bytes - msg := []byte{0xde, 0xad, 0xf0, 0x0d} + // generate a message (the size must be a multiple of the size of Fr) + var _msg fr.Element + _msg.SetRandom() + msg := _msg.Marshal() // sign the message signature, _ := privateKey.Sign(msg, hFunc) diff --git a/ecc/bls24-315/fr/mimc/decompose.go b/ecc/bls24-315/fr/mimc/decompose.go new file mode 100644 index 0000000000..4a962631fc --- /dev/null +++ b/ecc/bls24-315/fr/mimc/decompose.go @@ -0,0 +1,46 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package mimc + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" +) + +// Decompose interpret rawBytes as a bigInt x in big endian, +// and returns the digits of x (from LSB to MSB) when x is written +// in basis modulo. +func Decompose(rawBytes []byte) []fr.Element { + + rawBigInt := big.NewInt(0).SetBytes(rawBytes) + modulo := fr.Modulus() + + // maximum number of chunks that a function + maxNbChunks := len(rawBytes) / fr.Bytes + + res := make([]fr.Element, 0, maxNbChunks) + var tmp fr.Element + t := new(big.Int) + for rawBigInt.Sign() != 0 { + rawBigInt.DivMod(rawBigInt, modulo, t) + tmp.SetBigInt(t) + res = append(res, tmp) + } + + return res +} diff --git a/ecc/bls24-315/fr/mimc/decompose_test.go b/ecc/bls24-315/fr/mimc/decompose_test.go new file mode 100644 index 0000000000..817a588f22 --- /dev/null +++ b/ecc/bls24-315/fr/mimc/decompose_test.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package mimc + +import ( + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" +) + +func TestDecompose(t *testing.T) { + + // create 10 random digits in basis r + nbDigits := 10 + a := make([]fr.Element, nbDigits) + for i := 0; i < nbDigits; i++ { + a[i].SetRandom() + } + + // create a big int whose digits in basis r are a + m := fr.Modulus() + var b, tmp big.Int + for i := nbDigits - 1; i >= 0; i-- { + b.Mul(&b, m) + a[i].ToBigIntRegular(&tmp) + b.Add(&b, &tmp) + } + + // query the decomposition and compare to a + bb := b.Bytes() + d := Decompose(bb) + for i := 0; i < nbDigits; i++ { + if !d[i].Equal(&a[i]) { + t.Fatal("error decomposition") + } + } + +} diff --git a/ecc/bls24-315/fr/mimc/mimc.go b/ecc/bls24-315/fr/mimc/mimc.go index 63e8f5e1f8..f9971a900a 100644 --- a/ecc/bls24-315/fr/mimc/mimc.go +++ b/ecc/bls24-315/fr/mimc/mimc.go @@ -17,6 +17,7 @@ package mimc import ( + "errors" "hash" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" @@ -91,44 +92,44 @@ func (d *digest) BlockSize() int { } // Write (via the embedded io.Writer interface) adds more data to the running hash. -// It never returns an error. +// +// Each []byte block of size BlockSize represents a big endian fr.Element. +// +// If len(p) is not a multiple of BlockSize and any of the []byte in p represent an integer +// larger than fr.Modulus, this function returns an error. +// +// To hash arbitrary data ([]byte not representing canonical field elements) use Decompose +// function in this package. func (d *digest) Write(p []byte) (n int, err error) { n = len(p) + if n%BlockSize != 0 { + return 0, errors.New("invalid input length: must represent a list of field elements, expects a []byte of len m*BlockSize") + } + + // ensure each block represents a field element in canonical reduced form + for i := 0; i < n; i += BlockSize { + if _, err = fr.BigEndian.Element((*[BlockSize]byte)(p[i : i+BlockSize])); err != nil { + return 0, err + } + } + d.data = append(d.data, p...) return } -// Hash hash using Miyaguchi–Preneel: +// Hash hash using Miyaguchi-Preneel: // https://en.wikipedia.org/wiki/One-way_compression_function // The XOR operation is replaced by field addition, data is in Montgomery form func (d *digest) checksum() fr.Element { + // Write guarantees len(data) % BlockSize == 0 - var buffer [BlockSize]byte - var x fr.Element - - // if data size is not multiple of BlockSizes we padd: - // .. || 0xaf8 -> .. || 0x0000...0af8 - if len(d.data)%BlockSize != 0 { - q := len(d.data) / BlockSize - r := len(d.data) % BlockSize - sliceq := make([]byte, q*BlockSize) - copy(sliceq, d.data) - slicer := make([]byte, r) - copy(slicer, d.data[q*BlockSize:]) - sliceremainder := make([]byte, BlockSize-r) - d.data = append(sliceq, sliceremainder...) - d.data = append(d.data, slicer...) - } - + // TODO @ThomasPiellard shouldn't Sum() returns an error if there is no data? if len(d.data) == 0 { - d.data = make([]byte, 32) + d.data = make([]byte, BlockSize) } - nbChunks := len(d.data) / BlockSize - - for i := 0; i < nbChunks; i++ { - copy(buffer[:], d.data[i*BlockSize:(i+1)*BlockSize]) - x.SetBytes(buffer[:]) + for i := 0; i < len(d.data); i += BlockSize { + x, _ := fr.BigEndian.Element((*[BlockSize]byte)(d.data[i : i+BlockSize])) r := d.encrypt(x) d.h.Add(&r, &d.h).Add(&d.h, &x) } diff --git a/ecc/bls24-315/twistededwards/eddsa/eddsa_test.go b/ecc/bls24-315/twistededwards/eddsa/eddsa_test.go index 334b1cc0e1..669bce5e65 100644 --- a/ecc/bls24-315/twistededwards/eddsa/eddsa_test.go +++ b/ecc/bls24-315/twistededwards/eddsa/eddsa_test.go @@ -37,8 +37,10 @@ func Example() { privateKey, _ := GenerateKey(crand.Reader) publicKey := privateKey.PublicKey - // note that the message is on 4 bytes - msg := []byte{0xde, 0xad, 0xf0, 0x0d} + // generate a message (the size must be a multiple of the size of Fr) + var _msg fr.Element + _msg.SetRandom() + msg := _msg.Marshal() // sign the message signature, _ := privateKey.Sign(msg, hFunc) diff --git a/ecc/bls24-317/fr/mimc/decompose.go b/ecc/bls24-317/fr/mimc/decompose.go new file mode 100644 index 0000000000..b027d8bbc1 --- /dev/null +++ b/ecc/bls24-317/fr/mimc/decompose.go @@ -0,0 +1,46 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package mimc + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" +) + +// Decompose interpret rawBytes as a bigInt x in big endian, +// and returns the digits of x (from LSB to MSB) when x is written +// in basis modulo. +func Decompose(rawBytes []byte) []fr.Element { + + rawBigInt := big.NewInt(0).SetBytes(rawBytes) + modulo := fr.Modulus() + + // maximum number of chunks that a function + maxNbChunks := len(rawBytes) / fr.Bytes + + res := make([]fr.Element, 0, maxNbChunks) + var tmp fr.Element + t := new(big.Int) + for rawBigInt.Sign() != 0 { + rawBigInt.DivMod(rawBigInt, modulo, t) + tmp.SetBigInt(t) + res = append(res, tmp) + } + + return res +} diff --git a/ecc/bls24-317/fr/mimc/decompose_test.go b/ecc/bls24-317/fr/mimc/decompose_test.go new file mode 100644 index 0000000000..26a4769202 --- /dev/null +++ b/ecc/bls24-317/fr/mimc/decompose_test.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package mimc + +import ( + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" +) + +func TestDecompose(t *testing.T) { + + // create 10 random digits in basis r + nbDigits := 10 + a := make([]fr.Element, nbDigits) + for i := 0; i < nbDigits; i++ { + a[i].SetRandom() + } + + // create a big int whose digits in basis r are a + m := fr.Modulus() + var b, tmp big.Int + for i := nbDigits - 1; i >= 0; i-- { + b.Mul(&b, m) + a[i].ToBigIntRegular(&tmp) + b.Add(&b, &tmp) + } + + // query the decomposition and compare to a + bb := b.Bytes() + d := Decompose(bb) + for i := 0; i < nbDigits; i++ { + if !d[i].Equal(&a[i]) { + t.Fatal("error decomposition") + } + } + +} diff --git a/ecc/bls24-317/fr/mimc/mimc.go b/ecc/bls24-317/fr/mimc/mimc.go index 45a9262762..c950b05750 100644 --- a/ecc/bls24-317/fr/mimc/mimc.go +++ b/ecc/bls24-317/fr/mimc/mimc.go @@ -17,6 +17,7 @@ package mimc import ( + "errors" "hash" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" @@ -91,44 +92,44 @@ func (d *digest) BlockSize() int { } // Write (via the embedded io.Writer interface) adds more data to the running hash. -// It never returns an error. +// +// Each []byte block of size BlockSize represents a big endian fr.Element. +// +// If len(p) is not a multiple of BlockSize and any of the []byte in p represent an integer +// larger than fr.Modulus, this function returns an error. +// +// To hash arbitrary data ([]byte not representing canonical field elements) use Decompose +// function in this package. func (d *digest) Write(p []byte) (n int, err error) { n = len(p) + if n%BlockSize != 0 { + return 0, errors.New("invalid input length: must represent a list of field elements, expects a []byte of len m*BlockSize") + } + + // ensure each block represents a field element in canonical reduced form + for i := 0; i < n; i += BlockSize { + if _, err = fr.BigEndian.Element((*[BlockSize]byte)(p[i : i+BlockSize])); err != nil { + return 0, err + } + } + d.data = append(d.data, p...) return } -// Hash hash using Miyaguchi–Preneel: +// Hash hash using Miyaguchi-Preneel: // https://en.wikipedia.org/wiki/One-way_compression_function // The XOR operation is replaced by field addition, data is in Montgomery form func (d *digest) checksum() fr.Element { + // Write guarantees len(data) % BlockSize == 0 - var buffer [BlockSize]byte - var x fr.Element - - // if data size is not multiple of BlockSizes we padd: - // .. || 0xaf8 -> .. || 0x0000...0af8 - if len(d.data)%BlockSize != 0 { - q := len(d.data) / BlockSize - r := len(d.data) % BlockSize - sliceq := make([]byte, q*BlockSize) - copy(sliceq, d.data) - slicer := make([]byte, r) - copy(slicer, d.data[q*BlockSize:]) - sliceremainder := make([]byte, BlockSize-r) - d.data = append(sliceq, sliceremainder...) - d.data = append(d.data, slicer...) - } - + // TODO @ThomasPiellard shouldn't Sum() returns an error if there is no data? if len(d.data) == 0 { - d.data = make([]byte, 32) + d.data = make([]byte, BlockSize) } - nbChunks := len(d.data) / BlockSize - - for i := 0; i < nbChunks; i++ { - copy(buffer[:], d.data[i*BlockSize:(i+1)*BlockSize]) - x.SetBytes(buffer[:]) + for i := 0; i < len(d.data); i += BlockSize { + x, _ := fr.BigEndian.Element((*[BlockSize]byte)(d.data[i : i+BlockSize])) r := d.encrypt(x) d.h.Add(&r, &d.h).Add(&d.h, &x) } diff --git a/ecc/bls24-317/twistededwards/eddsa/eddsa_test.go b/ecc/bls24-317/twistededwards/eddsa/eddsa_test.go index 776d3894a4..34464874cd 100644 --- a/ecc/bls24-317/twistededwards/eddsa/eddsa_test.go +++ b/ecc/bls24-317/twistededwards/eddsa/eddsa_test.go @@ -37,8 +37,10 @@ func Example() { privateKey, _ := GenerateKey(crand.Reader) publicKey := privateKey.PublicKey - // note that the message is on 4 bytes - msg := []byte{0xde, 0xad, 0xf0, 0x0d} + // generate a message (the size must be a multiple of the size of Fr) + var _msg fr.Element + _msg.SetRandom() + msg := _msg.Marshal() // sign the message signature, _ := privateKey.Sign(msg, hFunc) diff --git a/ecc/bn254/fr/mimc/decompose.go b/ecc/bn254/fr/mimc/decompose.go new file mode 100644 index 0000000000..e61417b9bb --- /dev/null +++ b/ecc/bn254/fr/mimc/decompose.go @@ -0,0 +1,46 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package mimc + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +// Decompose interpret rawBytes as a bigInt x in big endian, +// and returns the digits of x (from LSB to MSB) when x is written +// in basis modulo. +func Decompose(rawBytes []byte) []fr.Element { + + rawBigInt := big.NewInt(0).SetBytes(rawBytes) + modulo := fr.Modulus() + + // maximum number of chunks that a function + maxNbChunks := len(rawBytes) / fr.Bytes + + res := make([]fr.Element, 0, maxNbChunks) + var tmp fr.Element + t := new(big.Int) + for rawBigInt.Sign() != 0 { + rawBigInt.DivMod(rawBigInt, modulo, t) + tmp.SetBigInt(t) + res = append(res, tmp) + } + + return res +} diff --git a/ecc/bn254/fr/mimc/decompose_test.go b/ecc/bn254/fr/mimc/decompose_test.go new file mode 100644 index 0000000000..3597da7a38 --- /dev/null +++ b/ecc/bn254/fr/mimc/decompose_test.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package mimc + +import ( + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +func TestDecompose(t *testing.T) { + + // create 10 random digits in basis r + nbDigits := 10 + a := make([]fr.Element, nbDigits) + for i := 0; i < nbDigits; i++ { + a[i].SetRandom() + } + + // create a big int whose digits in basis r are a + m := fr.Modulus() + var b, tmp big.Int + for i := nbDigits - 1; i >= 0; i-- { + b.Mul(&b, m) + a[i].ToBigIntRegular(&tmp) + b.Add(&b, &tmp) + } + + // query the decomposition and compare to a + bb := b.Bytes() + d := Decompose(bb) + for i := 0; i < nbDigits; i++ { + if !d[i].Equal(&a[i]) { + t.Fatal("error decomposition") + } + } + +} diff --git a/ecc/bn254/fr/mimc/mimc.go b/ecc/bn254/fr/mimc/mimc.go index 43cc82ec43..87a9776eef 100644 --- a/ecc/bn254/fr/mimc/mimc.go +++ b/ecc/bn254/fr/mimc/mimc.go @@ -17,6 +17,7 @@ package mimc import ( + "errors" "hash" "github.com/consensys/gnark-crypto/ecc/bn254/fr" @@ -91,44 +92,44 @@ func (d *digest) BlockSize() int { } // Write (via the embedded io.Writer interface) adds more data to the running hash. -// It never returns an error. +// +// Each []byte block of size BlockSize represents a big endian fr.Element. +// +// If len(p) is not a multiple of BlockSize and any of the []byte in p represent an integer +// larger than fr.Modulus, this function returns an error. +// +// To hash arbitrary data ([]byte not representing canonical field elements) use Decompose +// function in this package. func (d *digest) Write(p []byte) (n int, err error) { n = len(p) + if n%BlockSize != 0 { + return 0, errors.New("invalid input length: must represent a list of field elements, expects a []byte of len m*BlockSize") + } + + // ensure each block represents a field element in canonical reduced form + for i := 0; i < n; i += BlockSize { + if _, err = fr.BigEndian.Element((*[BlockSize]byte)(p[i : i+BlockSize])); err != nil { + return 0, err + } + } + d.data = append(d.data, p...) return } -// Hash hash using Miyaguchi–Preneel: +// Hash hash using Miyaguchi-Preneel: // https://en.wikipedia.org/wiki/One-way_compression_function // The XOR operation is replaced by field addition, data is in Montgomery form func (d *digest) checksum() fr.Element { + // Write guarantees len(data) % BlockSize == 0 - var buffer [BlockSize]byte - var x fr.Element - - // if data size is not multiple of BlockSizes we padd: - // .. || 0xaf8 -> .. || 0x0000...0af8 - if len(d.data)%BlockSize != 0 { - q := len(d.data) / BlockSize - r := len(d.data) % BlockSize - sliceq := make([]byte, q*BlockSize) - copy(sliceq, d.data) - slicer := make([]byte, r) - copy(slicer, d.data[q*BlockSize:]) - sliceremainder := make([]byte, BlockSize-r) - d.data = append(sliceq, sliceremainder...) - d.data = append(d.data, slicer...) - } - + // TODO @ThomasPiellard shouldn't Sum() returns an error if there is no data? if len(d.data) == 0 { - d.data = make([]byte, 32) + d.data = make([]byte, BlockSize) } - nbChunks := len(d.data) / BlockSize - - for i := 0; i < nbChunks; i++ { - copy(buffer[:], d.data[i*BlockSize:(i+1)*BlockSize]) - x.SetBytes(buffer[:]) + for i := 0; i < len(d.data); i += BlockSize { + x, _ := fr.BigEndian.Element((*[BlockSize]byte)(d.data[i : i+BlockSize])) r := d.encrypt(x) d.h.Add(&r, &d.h).Add(&d.h, &x) } diff --git a/ecc/bn254/fr/mimc/mimc_test.go b/ecc/bn254/fr/mimc/mimc_test.go deleted file mode 100644 index cb8995c030..0000000000 --- a/ecc/bn254/fr/mimc/mimc_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package mimc - -// import ( -// "testing" -// ) - -// func TestMimc(t *testing.T) { - -// // Expected result from ethereum -// var data [3]fr.Element -// data[0].SetString("10909369219534740878285360918369814291778422174980871969149168794639722256599") -// data[1].SetString("3811523387212735178398974960485340561880938762308498768570292593755555588442") -// data[2].SetString("21761276089180230617904476026690048826689721630933485969915548849196498965166") - -// h := NewMiMC() -// h.Write(data[0].Marshal()) -// h.Write(data[1].Marshal()) -// h.Write(data[2].Marshal()) - -// r := h.Sum(nil) - -// var b big.Int -// b.SetBytes(r) -// fmt.Printf("%s\n", b.String()) - -//------- - -// h := NewMiMC("mimc") -// var a [3]fr.Element -// a[0].SetRandom() -// a[1].SetRandom() -// a[2].SetRandom() -// fmt.Printf("%s\n", a[0].String()) -// fmt.Printf("%s\n", a[1].String()) -// fmt.Printf("%s\n", a[2].String()) -// fmt.Println("") -// h.Write(a[0].Marshal()) -// h.Write(a[1].Marshal()) -// h.Write(a[2].Marshal()) -// var a fr.Element -// a.SetUint64(2323) -// h.Write(a.Marshal()) -// r := h.Sum(nil) -// var br big.Int -// br.SetBytes(r) -// fmt.Printf("%s\n", br.String()) -//_h := h.(*digest) - -// //var h1, h2, h3 fr.Element -// var h1, h2 fr.Element -// h1.SetString("948723") -// h2.SetString("236878") -// // h3.SetString("283") -// _h.data = append(_h.data, h1.Marshal()...) -// _h.data = append(_h.data, h2.Marshal()...) -// // _h.data = append(_h.data, h3.Marshal()...) - -// _h.checksum() -// fmt.Printf("%s\n", _h.h.String()) -// } diff --git a/ecc/bn254/twistededwards/eddsa/eddsa_test.go b/ecc/bn254/twistededwards/eddsa/eddsa_test.go index c05a995a8d..3bf8c9d989 100644 --- a/ecc/bn254/twistededwards/eddsa/eddsa_test.go +++ b/ecc/bn254/twistededwards/eddsa/eddsa_test.go @@ -37,8 +37,10 @@ func Example() { privateKey, _ := GenerateKey(crand.Reader) publicKey := privateKey.PublicKey - // note that the message is on 4 bytes - msg := []byte{0xde, 0xad, 0xf0, 0x0d} + // generate a message (the size must be a multiple of the size of Fr) + var _msg fr.Element + _msg.SetRandom() + msg := _msg.Marshal() // sign the message signature, _ := privateKey.Sign(msg, hFunc) diff --git a/ecc/bw6-633/fr/mimc/decompose.go b/ecc/bw6-633/fr/mimc/decompose.go new file mode 100644 index 0000000000..0f4cc36c96 --- /dev/null +++ b/ecc/bw6-633/fr/mimc/decompose.go @@ -0,0 +1,46 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package mimc + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" +) + +// Decompose interpret rawBytes as a bigInt x in big endian, +// and returns the digits of x (from LSB to MSB) when x is written +// in basis modulo. +func Decompose(rawBytes []byte) []fr.Element { + + rawBigInt := big.NewInt(0).SetBytes(rawBytes) + modulo := fr.Modulus() + + // maximum number of chunks that a function + maxNbChunks := len(rawBytes) / fr.Bytes + + res := make([]fr.Element, 0, maxNbChunks) + var tmp fr.Element + t := new(big.Int) + for rawBigInt.Sign() != 0 { + rawBigInt.DivMod(rawBigInt, modulo, t) + tmp.SetBigInt(t) + res = append(res, tmp) + } + + return res +} diff --git a/ecc/bw6-633/fr/mimc/decompose_test.go b/ecc/bw6-633/fr/mimc/decompose_test.go new file mode 100644 index 0000000000..26518fd462 --- /dev/null +++ b/ecc/bw6-633/fr/mimc/decompose_test.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package mimc + +import ( + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" +) + +func TestDecompose(t *testing.T) { + + // create 10 random digits in basis r + nbDigits := 10 + a := make([]fr.Element, nbDigits) + for i := 0; i < nbDigits; i++ { + a[i].SetRandom() + } + + // create a big int whose digits in basis r are a + m := fr.Modulus() + var b, tmp big.Int + for i := nbDigits - 1; i >= 0; i-- { + b.Mul(&b, m) + a[i].ToBigIntRegular(&tmp) + b.Add(&b, &tmp) + } + + // query the decomposition and compare to a + bb := b.Bytes() + d := Decompose(bb) + for i := 0; i < nbDigits; i++ { + if !d[i].Equal(&a[i]) { + t.Fatal("error decomposition") + } + } + +} diff --git a/ecc/bw6-633/fr/mimc/mimc.go b/ecc/bw6-633/fr/mimc/mimc.go index 687bd79e46..d026855152 100644 --- a/ecc/bw6-633/fr/mimc/mimc.go +++ b/ecc/bw6-633/fr/mimc/mimc.go @@ -17,6 +17,7 @@ package mimc import ( + "errors" "hash" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" @@ -91,44 +92,44 @@ func (d *digest) BlockSize() int { } // Write (via the embedded io.Writer interface) adds more data to the running hash. -// It never returns an error. +// +// Each []byte block of size BlockSize represents a big endian fr.Element. +// +// If len(p) is not a multiple of BlockSize and any of the []byte in p represent an integer +// larger than fr.Modulus, this function returns an error. +// +// To hash arbitrary data ([]byte not representing canonical field elements) use Decompose +// function in this package. func (d *digest) Write(p []byte) (n int, err error) { n = len(p) + if n%BlockSize != 0 { + return 0, errors.New("invalid input length: must represent a list of field elements, expects a []byte of len m*BlockSize") + } + + // ensure each block represents a field element in canonical reduced form + for i := 0; i < n; i += BlockSize { + if _, err = fr.BigEndian.Element((*[BlockSize]byte)(p[i : i+BlockSize])); err != nil { + return 0, err + } + } + d.data = append(d.data, p...) return } -// Hash hash using Miyaguchi–Preneel: +// Hash hash using Miyaguchi-Preneel: // https://en.wikipedia.org/wiki/One-way_compression_function // The XOR operation is replaced by field addition, data is in Montgomery form func (d *digest) checksum() fr.Element { + // Write guarantees len(data) % BlockSize == 0 - var buffer [BlockSize]byte - var x fr.Element - - // if data size is not multiple of BlockSizes we padd: - // .. || 0xaf8 -> .. || 0x0000...0af8 - if len(d.data)%BlockSize != 0 { - q := len(d.data) / BlockSize - r := len(d.data) % BlockSize - sliceq := make([]byte, q*BlockSize) - copy(sliceq, d.data) - slicer := make([]byte, r) - copy(slicer, d.data[q*BlockSize:]) - sliceremainder := make([]byte, BlockSize-r) - d.data = append(sliceq, sliceremainder...) - d.data = append(d.data, slicer...) - } - + // TODO @ThomasPiellard shouldn't Sum() returns an error if there is no data? if len(d.data) == 0 { - d.data = make([]byte, 32) + d.data = make([]byte, BlockSize) } - nbChunks := len(d.data) / BlockSize - - for i := 0; i < nbChunks; i++ { - copy(buffer[:], d.data[i*BlockSize:(i+1)*BlockSize]) - x.SetBytes(buffer[:]) + for i := 0; i < len(d.data); i += BlockSize { + x, _ := fr.BigEndian.Element((*[BlockSize]byte)(d.data[i : i+BlockSize])) r := d.encrypt(x) d.h.Add(&r, &d.h).Add(&d.h, &x) } diff --git a/ecc/bw6-633/twistededwards/eddsa/eddsa_test.go b/ecc/bw6-633/twistededwards/eddsa/eddsa_test.go index 93e70b88ea..066a7ac20a 100644 --- a/ecc/bw6-633/twistededwards/eddsa/eddsa_test.go +++ b/ecc/bw6-633/twistededwards/eddsa/eddsa_test.go @@ -37,8 +37,10 @@ func Example() { privateKey, _ := GenerateKey(crand.Reader) publicKey := privateKey.PublicKey - // note that the message is on 4 bytes - msg := []byte{0xde, 0xad, 0xf0, 0x0d} + // generate a message (the size must be a multiple of the size of Fr) + var _msg fr.Element + _msg.SetRandom() + msg := _msg.Marshal() // sign the message signature, _ := privateKey.Sign(msg, hFunc) diff --git a/ecc/bw6-756/fr/mimc/decompose.go b/ecc/bw6-756/fr/mimc/decompose.go new file mode 100644 index 0000000000..c5bb70239e --- /dev/null +++ b/ecc/bw6-756/fr/mimc/decompose.go @@ -0,0 +1,46 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package mimc + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bw6-756/fr" +) + +// Decompose interpret rawBytes as a bigInt x in big endian, +// and returns the digits of x (from LSB to MSB) when x is written +// in basis modulo. +func Decompose(rawBytes []byte) []fr.Element { + + rawBigInt := big.NewInt(0).SetBytes(rawBytes) + modulo := fr.Modulus() + + // maximum number of chunks that a function + maxNbChunks := len(rawBytes) / fr.Bytes + + res := make([]fr.Element, 0, maxNbChunks) + var tmp fr.Element + t := new(big.Int) + for rawBigInt.Sign() != 0 { + rawBigInt.DivMod(rawBigInt, modulo, t) + tmp.SetBigInt(t) + res = append(res, tmp) + } + + return res +} diff --git a/ecc/bw6-756/fr/mimc/decompose_test.go b/ecc/bw6-756/fr/mimc/decompose_test.go new file mode 100644 index 0000000000..04d86a58c7 --- /dev/null +++ b/ecc/bw6-756/fr/mimc/decompose_test.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package mimc + +import ( + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bw6-756/fr" +) + +func TestDecompose(t *testing.T) { + + // create 10 random digits in basis r + nbDigits := 10 + a := make([]fr.Element, nbDigits) + for i := 0; i < nbDigits; i++ { + a[i].SetRandom() + } + + // create a big int whose digits in basis r are a + m := fr.Modulus() + var b, tmp big.Int + for i := nbDigits - 1; i >= 0; i-- { + b.Mul(&b, m) + a[i].ToBigIntRegular(&tmp) + b.Add(&b, &tmp) + } + + // query the decomposition and compare to a + bb := b.Bytes() + d := Decompose(bb) + for i := 0; i < nbDigits; i++ { + if !d[i].Equal(&a[i]) { + t.Fatal("error decomposition") + } + } + +} diff --git a/ecc/bw6-756/fr/mimc/mimc.go b/ecc/bw6-756/fr/mimc/mimc.go index 26f6bb9e84..9218a8e359 100644 --- a/ecc/bw6-756/fr/mimc/mimc.go +++ b/ecc/bw6-756/fr/mimc/mimc.go @@ -17,6 +17,7 @@ package mimc import ( + "errors" "hash" "github.com/consensys/gnark-crypto/ecc/bw6-756/fr" @@ -91,44 +92,44 @@ func (d *digest) BlockSize() int { } // Write (via the embedded io.Writer interface) adds more data to the running hash. -// It never returns an error. +// +// Each []byte block of size BlockSize represents a big endian fr.Element. +// +// If len(p) is not a multiple of BlockSize and any of the []byte in p represent an integer +// larger than fr.Modulus, this function returns an error. +// +// To hash arbitrary data ([]byte not representing canonical field elements) use Decompose +// function in this package. func (d *digest) Write(p []byte) (n int, err error) { n = len(p) + if n%BlockSize != 0 { + return 0, errors.New("invalid input length: must represent a list of field elements, expects a []byte of len m*BlockSize") + } + + // ensure each block represents a field element in canonical reduced form + for i := 0; i < n; i += BlockSize { + if _, err = fr.BigEndian.Element((*[BlockSize]byte)(p[i : i+BlockSize])); err != nil { + return 0, err + } + } + d.data = append(d.data, p...) return } -// Hash hash using Miyaguchi–Preneel: +// Hash hash using Miyaguchi-Preneel: // https://en.wikipedia.org/wiki/One-way_compression_function // The XOR operation is replaced by field addition, data is in Montgomery form func (d *digest) checksum() fr.Element { + // Write guarantees len(data) % BlockSize == 0 - var buffer [BlockSize]byte - var x fr.Element - - // if data size is not multiple of BlockSizes we padd: - // .. || 0xaf8 -> .. || 0x0000...0af8 - if len(d.data)%BlockSize != 0 { - q := len(d.data) / BlockSize - r := len(d.data) % BlockSize - sliceq := make([]byte, q*BlockSize) - copy(sliceq, d.data) - slicer := make([]byte, r) - copy(slicer, d.data[q*BlockSize:]) - sliceremainder := make([]byte, BlockSize-r) - d.data = append(sliceq, sliceremainder...) - d.data = append(d.data, slicer...) - } - + // TODO @ThomasPiellard shouldn't Sum() returns an error if there is no data? if len(d.data) == 0 { - d.data = make([]byte, 32) + d.data = make([]byte, BlockSize) } - nbChunks := len(d.data) / BlockSize - - for i := 0; i < nbChunks; i++ { - copy(buffer[:], d.data[i*BlockSize:(i+1)*BlockSize]) - x.SetBytes(buffer[:]) + for i := 0; i < len(d.data); i += BlockSize { + x, _ := fr.BigEndian.Element((*[BlockSize]byte)(d.data[i : i+BlockSize])) r := d.encrypt(x) d.h.Add(&r, &d.h).Add(&d.h, &x) } diff --git a/ecc/bw6-756/twistededwards/eddsa/eddsa_test.go b/ecc/bw6-756/twistededwards/eddsa/eddsa_test.go index 8cc3ed1f41..82388cfdd4 100644 --- a/ecc/bw6-756/twistededwards/eddsa/eddsa_test.go +++ b/ecc/bw6-756/twistededwards/eddsa/eddsa_test.go @@ -37,8 +37,10 @@ func Example() { privateKey, _ := GenerateKey(crand.Reader) publicKey := privateKey.PublicKey - // note that the message is on 4 bytes - msg := []byte{0xde, 0xad, 0xf0, 0x0d} + // generate a message (the size must be a multiple of the size of Fr) + var _msg fr.Element + _msg.SetRandom() + msg := _msg.Marshal() // sign the message signature, _ := privateKey.Sign(msg, hFunc) diff --git a/ecc/bw6-761/fr/mimc/decompose.go b/ecc/bw6-761/fr/mimc/decompose.go new file mode 100644 index 0000000000..06761e28fe --- /dev/null +++ b/ecc/bw6-761/fr/mimc/decompose.go @@ -0,0 +1,46 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package mimc + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" +) + +// Decompose interpret rawBytes as a bigInt x in big endian, +// and returns the digits of x (from LSB to MSB) when x is written +// in basis modulo. +func Decompose(rawBytes []byte) []fr.Element { + + rawBigInt := big.NewInt(0).SetBytes(rawBytes) + modulo := fr.Modulus() + + // maximum number of chunks that a function + maxNbChunks := len(rawBytes) / fr.Bytes + + res := make([]fr.Element, 0, maxNbChunks) + var tmp fr.Element + t := new(big.Int) + for rawBigInt.Sign() != 0 { + rawBigInt.DivMod(rawBigInt, modulo, t) + tmp.SetBigInt(t) + res = append(res, tmp) + } + + return res +} diff --git a/ecc/bw6-761/fr/mimc/decompose_test.go b/ecc/bw6-761/fr/mimc/decompose_test.go new file mode 100644 index 0000000000..031367811e --- /dev/null +++ b/ecc/bw6-761/fr/mimc/decompose_test.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package mimc + +import ( + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" +) + +func TestDecompose(t *testing.T) { + + // create 10 random digits in basis r + nbDigits := 10 + a := make([]fr.Element, nbDigits) + for i := 0; i < nbDigits; i++ { + a[i].SetRandom() + } + + // create a big int whose digits in basis r are a + m := fr.Modulus() + var b, tmp big.Int + for i := nbDigits - 1; i >= 0; i-- { + b.Mul(&b, m) + a[i].ToBigIntRegular(&tmp) + b.Add(&b, &tmp) + } + + // query the decomposition and compare to a + bb := b.Bytes() + d := Decompose(bb) + for i := 0; i < nbDigits; i++ { + if !d[i].Equal(&a[i]) { + t.Fatal("error decomposition") + } + } + +} diff --git a/ecc/bw6-761/fr/mimc/mimc.go b/ecc/bw6-761/fr/mimc/mimc.go index 5c8bc52e7b..3b69ba02b7 100644 --- a/ecc/bw6-761/fr/mimc/mimc.go +++ b/ecc/bw6-761/fr/mimc/mimc.go @@ -17,6 +17,7 @@ package mimc import ( + "errors" "hash" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" @@ -91,44 +92,44 @@ func (d *digest) BlockSize() int { } // Write (via the embedded io.Writer interface) adds more data to the running hash. -// It never returns an error. +// +// Each []byte block of size BlockSize represents a big endian fr.Element. +// +// If len(p) is not a multiple of BlockSize and any of the []byte in p represent an integer +// larger than fr.Modulus, this function returns an error. +// +// To hash arbitrary data ([]byte not representing canonical field elements) use Decompose +// function in this package. func (d *digest) Write(p []byte) (n int, err error) { n = len(p) + if n%BlockSize != 0 { + return 0, errors.New("invalid input length: must represent a list of field elements, expects a []byte of len m*BlockSize") + } + + // ensure each block represents a field element in canonical reduced form + for i := 0; i < n; i += BlockSize { + if _, err = fr.BigEndian.Element((*[BlockSize]byte)(p[i : i+BlockSize])); err != nil { + return 0, err + } + } + d.data = append(d.data, p...) return } -// Hash hash using Miyaguchi–Preneel: +// Hash hash using Miyaguchi-Preneel: // https://en.wikipedia.org/wiki/One-way_compression_function // The XOR operation is replaced by field addition, data is in Montgomery form func (d *digest) checksum() fr.Element { + // Write guarantees len(data) % BlockSize == 0 - var buffer [BlockSize]byte - var x fr.Element - - // if data size is not multiple of BlockSizes we padd: - // .. || 0xaf8 -> .. || 0x0000...0af8 - if len(d.data)%BlockSize != 0 { - q := len(d.data) / BlockSize - r := len(d.data) % BlockSize - sliceq := make([]byte, q*BlockSize) - copy(sliceq, d.data) - slicer := make([]byte, r) - copy(slicer, d.data[q*BlockSize:]) - sliceremainder := make([]byte, BlockSize-r) - d.data = append(sliceq, sliceremainder...) - d.data = append(d.data, slicer...) - } - + // TODO @ThomasPiellard shouldn't Sum() returns an error if there is no data? if len(d.data) == 0 { - d.data = make([]byte, 32) + d.data = make([]byte, BlockSize) } - nbChunks := len(d.data) / BlockSize - - for i := 0; i < nbChunks; i++ { - copy(buffer[:], d.data[i*BlockSize:(i+1)*BlockSize]) - x.SetBytes(buffer[:]) + for i := 0; i < len(d.data); i += BlockSize { + x, _ := fr.BigEndian.Element((*[BlockSize]byte)(d.data[i : i+BlockSize])) r := d.encrypt(x) d.h.Add(&r, &d.h).Add(&d.h, &x) } diff --git a/ecc/bw6-761/twistededwards/eddsa/eddsa_test.go b/ecc/bw6-761/twistededwards/eddsa/eddsa_test.go index 6918f7c441..f8929c461a 100644 --- a/ecc/bw6-761/twistededwards/eddsa/eddsa_test.go +++ b/ecc/bw6-761/twistededwards/eddsa/eddsa_test.go @@ -37,8 +37,10 @@ func Example() { privateKey, _ := GenerateKey(crand.Reader) publicKey := privateKey.PublicKey - // note that the message is on 4 bytes - msg := []byte{0xde, 0xad, 0xf0, 0x0d} + // generate a message (the size must be a multiple of the size of Fr) + var _msg fr.Element + _msg.SetRandom() + msg := _msg.Marshal() // sign the message signature, _ := privateKey.Sign(msg, hFunc) diff --git a/internal/generator/crypto/hash/mimc/generate.go b/internal/generator/crypto/hash/mimc/generate.go index 92055938c3..94caf7f56c 100644 --- a/internal/generator/crypto/hash/mimc/generate.go +++ b/internal/generator/crypto/hash/mimc/generate.go @@ -1,6 +1,7 @@ package mimc import ( + "os" "path/filepath" "github.com/consensys/bavard" @@ -16,7 +17,11 @@ func Generate(conf config.Curve, baseDir string, bgen *bavard.BatchGenerator) er entries := []bavard.Entry{ {File: filepath.Join(baseDir, "doc.go"), Templates: []string{"doc.go.tmpl"}}, {File: filepath.Join(baseDir, "mimc.go"), Templates: []string{"mimc.go.tmpl"}}, + {File: filepath.Join(baseDir, "decompose.go"), Templates: []string{"decompose.go.tmpl"}}, + {File: filepath.Join(baseDir, "decompose_test.go"), Templates: []string{"tests/decompose.go.tmpl"}}, } + os.Remove(filepath.Join(baseDir, "utils.go")) + os.Remove(filepath.Join(baseDir, "utils_test.go")) return bgen.Generate(conf, conf.Package, "./crypto/hash/mimc/template", entries...) } diff --git a/internal/generator/crypto/hash/mimc/template/decompose.go.tmpl b/internal/generator/crypto/hash/mimc/template/decompose.go.tmpl new file mode 100644 index 0000000000..1658a9e1d0 --- /dev/null +++ b/internal/generator/crypto/hash/mimc/template/decompose.go.tmpl @@ -0,0 +1,28 @@ + +import ( "math/big" + + "github.com/consensys/gnark-crypto/ecc/{{ .Name }}/fr" +) + +// Decompose interpret rawBytes as a bigInt x in big endian, +// and returns the digits of x (from LSB to MSB) when x is written +// in basis modulo. +func Decompose(rawBytes []byte) []fr.Element { + + rawBigInt := big.NewInt(0).SetBytes(rawBytes) + modulo := fr.Modulus() + + // maximum number of chunks that a function + maxNbChunks := len(rawBytes) / fr.Bytes + + res := make([]fr.Element, 0, maxNbChunks) + var tmp fr.Element + t := new(big.Int) + for rawBigInt.Sign() != 0 { + rawBigInt.DivMod(rawBigInt, modulo, t) + tmp.SetBigInt(t) + res = append(res, tmp) + } + + return res +} diff --git a/internal/generator/crypto/hash/mimc/template/mimc.go.tmpl b/internal/generator/crypto/hash/mimc/template/mimc.go.tmpl index b14de2c01b..463a6767ce 100644 --- a/internal/generator/crypto/hash/mimc/template/mimc.go.tmpl +++ b/internal/generator/crypto/hash/mimc/template/mimc.go.tmpl @@ -1,5 +1,6 @@ import ( "hash" + "errors" "math/big" "github.com/consensys/gnark-crypto/ecc/{{ .Name }}/fr" @@ -77,44 +78,44 @@ func (d *digest) BlockSize() int { } // Write (via the embedded io.Writer interface) adds more data to the running hash. -// It never returns an error. +// +// Each []byte block of size BlockSize represents a big endian fr.Element. +// +// If len(p) is not a multiple of BlockSize and any of the []byte in p represent an integer +// larger than fr.Modulus, this function returns an error. +// +// To hash arbitrary data ([]byte not representing canonical field elements) use Decompose +// function in this package. func (d *digest) Write(p []byte) (n int, err error) { n = len(p) + if n % BlockSize != 0 { + return 0, errors.New("invalid input length: must represent a list of field elements, expects a []byte of len m*BlockSize") + } + + // ensure each block represents a field element in canonical reduced form + for i := 0; i < n; i += BlockSize { + if _, err = fr.BigEndian.Element((*[BlockSize]byte)(p[i:i+BlockSize])); err != nil { + return 0, err + } + } + d.data = append(d.data, p...) return } -// Hash hash using Miyaguchi–Preneel: +// Hash hash using Miyaguchi-Preneel: // https://en.wikipedia.org/wiki/One-way_compression_function // The XOR operation is replaced by field addition, data is in Montgomery form func (d *digest) checksum() fr.Element { - - var buffer [BlockSize]byte - var x fr.Element - - // if data size is not multiple of BlockSizes we padd: - // .. || 0xaf8 -> .. || 0x0000...0af8 - if len(d.data)%BlockSize != 0 { - q := len(d.data) / BlockSize - r := len(d.data) % BlockSize - sliceq := make([]byte, q*BlockSize) - copy(sliceq, d.data) - slicer := make([]byte, r) - copy(slicer, d.data[q*BlockSize:]) - sliceremainder := make([]byte, BlockSize-r) - d.data = append(sliceq, sliceremainder...) - d.data = append(d.data, slicer...) - } - - if len(d.data) == 0 { - d.data = make([]byte, 32) + // Write guarantees len(data) % BlockSize == 0 + + // TODO @ThomasPiellard shouldn't Sum() returns an error if there is no data? + if len(d.data) == 0 { + d.data = make([]byte, BlockSize) } - nbChunks := len(d.data) / BlockSize - - for i := 0; i < nbChunks; i++ { - copy(buffer[:], d.data[i*BlockSize:(i+1)*BlockSize]) - x.SetBytes(buffer[:]) + for i := 0; i < len(d.data); i+=BlockSize { + x, _ := fr.BigEndian.Element((*[BlockSize]byte)(d.data[i:i+BlockSize])) r := d.encrypt(x) d.h.Add(&r, &d.h).Add(&d.h, &x) } diff --git a/internal/generator/crypto/hash/mimc/template/tests/decompose.go.tmpl b/internal/generator/crypto/hash/mimc/template/tests/decompose.go.tmpl new file mode 100644 index 0000000000..26dc6661f4 --- /dev/null +++ b/internal/generator/crypto/hash/mimc/template/tests/decompose.go.tmpl @@ -0,0 +1,35 @@ +import ( + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc/{{ .Name }}/fr" +) + +func TestDecompose(t *testing.T) { + + // create 10 random digits in basis r + nbDigits := 10 + a := make([]fr.Element, nbDigits) + for i := 0; i < nbDigits; i++ { + a[i].SetRandom() + } + + // create a big int whose digits in basis r are a + m := fr.Modulus() + var b, tmp big.Int + for i := nbDigits - 1; i >= 0; i-- { + b.Mul(&b, m) + a[i].ToBigIntRegular(&tmp) + b.Add(&b, &tmp) + } + + // query the decomposition and compare to a + bb := b.Bytes() + d := Decompose(bb) + for i := 0; i < nbDigits; i++ { + if !d[i].Equal(&a[i]) { + t.Fatal("error decomposition") + } + } + +} diff --git a/internal/generator/edwards/eddsa/template/eddsa.test.go.tmpl b/internal/generator/edwards/eddsa/template/eddsa.test.go.tmpl index 09a2b32e73..0f0f04effb 100644 --- a/internal/generator/edwards/eddsa/template/eddsa.test.go.tmpl +++ b/internal/generator/edwards/eddsa/template/eddsa.test.go.tmpl @@ -20,8 +20,10 @@ func Example() { privateKey, _ := GenerateKey(crand.Reader) publicKey := privateKey.PublicKey - // note that the message is on 4 bytes - msg := []byte{0xde, 0xad, 0xf0, 0x0d} + // generate a message (the size must be a multiple of the size of Fr) + var _msg fr.Element + _msg.SetRandom() + msg := _msg.Marshal() // sign the message signature, _ := privateKey.Sign(msg, hFunc) diff --git a/utils/decompose.go b/utils/decompose.go new file mode 100644 index 0000000000..dc847b696d --- /dev/null +++ b/utils/decompose.go @@ -0,0 +1,38 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License.s + +package utils + +import "math/big" + +// Decompose interpret rawBytes as a bigInt x in big endian, +// and returns the digits of x (from LSB to MSB) when x is written +// in basis modulo. +func Decompose(rawBytes []byte, modulo *big.Int) (decomposed []byte) { + raw := big.NewInt(0).SetBytes(rawBytes) + + var chunk [32]byte + decomposed = make([]byte, 0, len(rawBytes)) + for raw.Cmp(modulo) >= 0 { + mod := big.NewInt(0).Mod(raw, modulo) + mod.FillBytes(chunk[:]) + decomposed = append(decomposed, chunk[:]...) + + raw.Div(raw, modulo) + } + + raw.FillBytes(chunk[:]) + decomposed = append(decomposed, chunk[:]...) + return decomposed +}