From fef2b26e59d1408219ff6fac871136b20cfabeb7 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 25 Jan 2023 14:10:59 +0100 Subject: [PATCH 1/7] chore(templates): move ecdsa to signature dir --- ecc/bls12-377/{ => signature}/ecdsa/doc.go | 0 ecc/bls12-377/{ => signature}/ecdsa/ecdsa.go | 0 ecc/bls12-377/{ => signature}/ecdsa/ecdsa_test.go | 0 ecc/bls12-377/{ => signature}/ecdsa/marshal.go | 0 ecc/bls12-377/{ => signature}/ecdsa/marshal_test.go | 0 ecc/bls12-378/{ => signature}/ecdsa/doc.go | 0 ecc/bls12-378/{ => signature}/ecdsa/ecdsa.go | 0 ecc/bls12-378/{ => signature}/ecdsa/ecdsa_test.go | 0 ecc/bls12-378/{ => signature}/ecdsa/marshal.go | 0 ecc/bls12-378/{ => signature}/ecdsa/marshal_test.go | 0 ecc/bls12-381/{ => signature}/ecdsa/doc.go | 0 ecc/bls12-381/{ => signature}/ecdsa/ecdsa.go | 0 ecc/bls12-381/{ => signature}/ecdsa/ecdsa_test.go | 0 ecc/bls12-381/{ => signature}/ecdsa/marshal.go | 0 ecc/bls12-381/{ => signature}/ecdsa/marshal_test.go | 0 ecc/bls24-315/{ => signature}/ecdsa/doc.go | 0 ecc/bls24-315/{ => signature}/ecdsa/ecdsa.go | 0 ecc/bls24-315/{ => signature}/ecdsa/ecdsa_test.go | 0 ecc/bls24-315/{ => signature}/ecdsa/marshal.go | 0 ecc/bls24-315/{ => signature}/ecdsa/marshal_test.go | 0 ecc/bls24-317/{ => signature}/ecdsa/doc.go | 0 ecc/bls24-317/{ => signature}/ecdsa/ecdsa.go | 0 ecc/bls24-317/{ => signature}/ecdsa/ecdsa_test.go | 0 ecc/bls24-317/{ => signature}/ecdsa/marshal.go | 0 ecc/bls24-317/{ => signature}/ecdsa/marshal_test.go | 0 ecc/bn254/{ => signature}/ecdsa/doc.go | 0 ecc/bn254/{ => signature}/ecdsa/ecdsa.go | 0 ecc/bn254/{ => signature}/ecdsa/ecdsa_test.go | 0 ecc/bn254/{ => signature}/ecdsa/marshal.go | 0 ecc/bn254/{ => signature}/ecdsa/marshal_test.go | 0 ecc/bw6-633/{ => signature}/ecdsa/doc.go | 0 ecc/bw6-633/{ => signature}/ecdsa/ecdsa.go | 0 ecc/bw6-633/{ => signature}/ecdsa/ecdsa_test.go | 0 ecc/bw6-633/{ => signature}/ecdsa/marshal.go | 0 ecc/bw6-633/{ => signature}/ecdsa/marshal_test.go | 0 ecc/bw6-756/{ => signature}/ecdsa/doc.go | 0 ecc/bw6-756/{ => signature}/ecdsa/ecdsa.go | 0 ecc/bw6-756/{ => signature}/ecdsa/ecdsa_test.go | 0 ecc/bw6-756/{ => signature}/ecdsa/marshal.go | 0 ecc/bw6-756/{ => signature}/ecdsa/marshal_test.go | 0 ecc/bw6-761/{ => signature}/ecdsa/doc.go | 0 ecc/bw6-761/{ => signature}/ecdsa/ecdsa.go | 0 ecc/bw6-761/{ => signature}/ecdsa/ecdsa_test.go | 0 ecc/bw6-761/{ => signature}/ecdsa/marshal.go | 0 ecc/bw6-761/{ => signature}/ecdsa/marshal_test.go | 0 ecc/secp256k1/{ => signature}/ecdsa/doc.go | 0 ecc/secp256k1/{ => signature}/ecdsa/ecdsa.go | 0 ecc/secp256k1/{ => signature}/ecdsa/ecdsa_test.go | 0 ecc/secp256k1/{ => signature}/ecdsa/marshal.go | 0 ecc/secp256k1/{ => signature}/ecdsa/marshal_test.go | 0 ecc/stark-curve/{ => signature}/ecdsa/doc.go | 0 ecc/stark-curve/{ => signature}/ecdsa/ecdsa.go | 0 ecc/stark-curve/{ => signature}/ecdsa/ecdsa_test.go | 0 ecc/stark-curve/{ => signature}/ecdsa/marshal.go | 0 ecc/stark-curve/{ => signature}/ecdsa/marshal_test.go | 0 internal/generator/main.go | 4 ++-- internal/generator/{ => signature}/ecdsa/generate.go | 2 +- internal/generator/{ => signature}/ecdsa/template/doc.go.tmpl | 0 .../generator/{ => signature}/ecdsa/template/ecdsa.go.tmpl | 0 .../{ => signature}/ecdsa/template/ecdsa.test.go.tmpl | 0 .../generator/{ => signature}/ecdsa/template/marshal.go.tmpl | 0 .../{ => signature}/ecdsa/template/marshal.test.go.tmpl | 0 62 files changed, 3 insertions(+), 3 deletions(-) rename ecc/bls12-377/{ => signature}/ecdsa/doc.go (100%) rename ecc/bls12-377/{ => signature}/ecdsa/ecdsa.go (100%) rename ecc/bls12-377/{ => signature}/ecdsa/ecdsa_test.go (100%) rename ecc/bls12-377/{ => signature}/ecdsa/marshal.go (100%) rename ecc/bls12-377/{ => signature}/ecdsa/marshal_test.go (100%) rename ecc/bls12-378/{ => signature}/ecdsa/doc.go (100%) rename ecc/bls12-378/{ => signature}/ecdsa/ecdsa.go (100%) rename ecc/bls12-378/{ => signature}/ecdsa/ecdsa_test.go (100%) rename ecc/bls12-378/{ => signature}/ecdsa/marshal.go (100%) rename ecc/bls12-378/{ => signature}/ecdsa/marshal_test.go (100%) rename ecc/bls12-381/{ => signature}/ecdsa/doc.go (100%) rename ecc/bls12-381/{ => signature}/ecdsa/ecdsa.go (100%) rename ecc/bls12-381/{ => signature}/ecdsa/ecdsa_test.go (100%) rename ecc/bls12-381/{ => signature}/ecdsa/marshal.go (100%) rename ecc/bls12-381/{ => signature}/ecdsa/marshal_test.go (100%) rename ecc/bls24-315/{ => signature}/ecdsa/doc.go (100%) rename ecc/bls24-315/{ => signature}/ecdsa/ecdsa.go (100%) rename ecc/bls24-315/{ => signature}/ecdsa/ecdsa_test.go (100%) rename ecc/bls24-315/{ => signature}/ecdsa/marshal.go (100%) rename ecc/bls24-315/{ => signature}/ecdsa/marshal_test.go (100%) rename ecc/bls24-317/{ => signature}/ecdsa/doc.go (100%) rename ecc/bls24-317/{ => signature}/ecdsa/ecdsa.go (100%) rename ecc/bls24-317/{ => signature}/ecdsa/ecdsa_test.go (100%) rename ecc/bls24-317/{ => signature}/ecdsa/marshal.go (100%) rename ecc/bls24-317/{ => signature}/ecdsa/marshal_test.go (100%) rename ecc/bn254/{ => signature}/ecdsa/doc.go (100%) rename ecc/bn254/{ => signature}/ecdsa/ecdsa.go (100%) rename ecc/bn254/{ => signature}/ecdsa/ecdsa_test.go (100%) rename ecc/bn254/{ => signature}/ecdsa/marshal.go (100%) rename ecc/bn254/{ => signature}/ecdsa/marshal_test.go (100%) rename ecc/bw6-633/{ => signature}/ecdsa/doc.go (100%) rename ecc/bw6-633/{ => signature}/ecdsa/ecdsa.go (100%) rename ecc/bw6-633/{ => signature}/ecdsa/ecdsa_test.go (100%) rename ecc/bw6-633/{ => signature}/ecdsa/marshal.go (100%) rename ecc/bw6-633/{ => signature}/ecdsa/marshal_test.go (100%) rename ecc/bw6-756/{ => signature}/ecdsa/doc.go (100%) rename ecc/bw6-756/{ => signature}/ecdsa/ecdsa.go (100%) rename ecc/bw6-756/{ => signature}/ecdsa/ecdsa_test.go (100%) rename ecc/bw6-756/{ => signature}/ecdsa/marshal.go (100%) rename ecc/bw6-756/{ => signature}/ecdsa/marshal_test.go (100%) rename ecc/bw6-761/{ => signature}/ecdsa/doc.go (100%) rename ecc/bw6-761/{ => signature}/ecdsa/ecdsa.go (100%) rename ecc/bw6-761/{ => signature}/ecdsa/ecdsa_test.go (100%) rename ecc/bw6-761/{ => signature}/ecdsa/marshal.go (100%) rename ecc/bw6-761/{ => signature}/ecdsa/marshal_test.go (100%) rename ecc/secp256k1/{ => signature}/ecdsa/doc.go (100%) rename ecc/secp256k1/{ => signature}/ecdsa/ecdsa.go (100%) rename ecc/secp256k1/{ => signature}/ecdsa/ecdsa_test.go (100%) rename ecc/secp256k1/{ => signature}/ecdsa/marshal.go (100%) rename ecc/secp256k1/{ => signature}/ecdsa/marshal_test.go (100%) rename ecc/stark-curve/{ => signature}/ecdsa/doc.go (100%) rename ecc/stark-curve/{ => signature}/ecdsa/ecdsa.go (100%) rename ecc/stark-curve/{ => signature}/ecdsa/ecdsa_test.go (100%) rename ecc/stark-curve/{ => signature}/ecdsa/marshal.go (100%) rename ecc/stark-curve/{ => signature}/ecdsa/marshal_test.go (100%) rename internal/generator/{ => signature}/ecdsa/generate.go (90%) rename internal/generator/{ => signature}/ecdsa/template/doc.go.tmpl (100%) rename internal/generator/{ => signature}/ecdsa/template/ecdsa.go.tmpl (100%) rename internal/generator/{ => signature}/ecdsa/template/ecdsa.test.go.tmpl (100%) rename internal/generator/{ => signature}/ecdsa/template/marshal.go.tmpl (100%) rename internal/generator/{ => signature}/ecdsa/template/marshal.test.go.tmpl (100%) diff --git a/ecc/bls12-377/ecdsa/doc.go b/ecc/bls12-377/signature/ecdsa/doc.go similarity index 100% rename from ecc/bls12-377/ecdsa/doc.go rename to ecc/bls12-377/signature/ecdsa/doc.go diff --git a/ecc/bls12-377/ecdsa/ecdsa.go b/ecc/bls12-377/signature/ecdsa/ecdsa.go similarity index 100% rename from ecc/bls12-377/ecdsa/ecdsa.go rename to ecc/bls12-377/signature/ecdsa/ecdsa.go diff --git a/ecc/bls12-377/ecdsa/ecdsa_test.go b/ecc/bls12-377/signature/ecdsa/ecdsa_test.go similarity index 100% rename from ecc/bls12-377/ecdsa/ecdsa_test.go rename to ecc/bls12-377/signature/ecdsa/ecdsa_test.go diff --git a/ecc/bls12-377/ecdsa/marshal.go b/ecc/bls12-377/signature/ecdsa/marshal.go similarity index 100% rename from ecc/bls12-377/ecdsa/marshal.go rename to ecc/bls12-377/signature/ecdsa/marshal.go diff --git a/ecc/bls12-377/ecdsa/marshal_test.go b/ecc/bls12-377/signature/ecdsa/marshal_test.go similarity index 100% rename from ecc/bls12-377/ecdsa/marshal_test.go rename to ecc/bls12-377/signature/ecdsa/marshal_test.go diff --git a/ecc/bls12-378/ecdsa/doc.go b/ecc/bls12-378/signature/ecdsa/doc.go similarity index 100% rename from ecc/bls12-378/ecdsa/doc.go rename to ecc/bls12-378/signature/ecdsa/doc.go diff --git a/ecc/bls12-378/ecdsa/ecdsa.go b/ecc/bls12-378/signature/ecdsa/ecdsa.go similarity index 100% rename from ecc/bls12-378/ecdsa/ecdsa.go rename to ecc/bls12-378/signature/ecdsa/ecdsa.go diff --git a/ecc/bls12-378/ecdsa/ecdsa_test.go b/ecc/bls12-378/signature/ecdsa/ecdsa_test.go similarity index 100% rename from ecc/bls12-378/ecdsa/ecdsa_test.go rename to ecc/bls12-378/signature/ecdsa/ecdsa_test.go diff --git a/ecc/bls12-378/ecdsa/marshal.go b/ecc/bls12-378/signature/ecdsa/marshal.go similarity index 100% rename from ecc/bls12-378/ecdsa/marshal.go rename to ecc/bls12-378/signature/ecdsa/marshal.go diff --git a/ecc/bls12-378/ecdsa/marshal_test.go b/ecc/bls12-378/signature/ecdsa/marshal_test.go similarity index 100% rename from ecc/bls12-378/ecdsa/marshal_test.go rename to ecc/bls12-378/signature/ecdsa/marshal_test.go diff --git a/ecc/bls12-381/ecdsa/doc.go b/ecc/bls12-381/signature/ecdsa/doc.go similarity index 100% rename from ecc/bls12-381/ecdsa/doc.go rename to ecc/bls12-381/signature/ecdsa/doc.go diff --git a/ecc/bls12-381/ecdsa/ecdsa.go b/ecc/bls12-381/signature/ecdsa/ecdsa.go similarity index 100% rename from ecc/bls12-381/ecdsa/ecdsa.go rename to ecc/bls12-381/signature/ecdsa/ecdsa.go diff --git a/ecc/bls12-381/ecdsa/ecdsa_test.go b/ecc/bls12-381/signature/ecdsa/ecdsa_test.go similarity index 100% rename from ecc/bls12-381/ecdsa/ecdsa_test.go rename to ecc/bls12-381/signature/ecdsa/ecdsa_test.go diff --git a/ecc/bls12-381/ecdsa/marshal.go b/ecc/bls12-381/signature/ecdsa/marshal.go similarity index 100% rename from ecc/bls12-381/ecdsa/marshal.go rename to ecc/bls12-381/signature/ecdsa/marshal.go diff --git a/ecc/bls12-381/ecdsa/marshal_test.go b/ecc/bls12-381/signature/ecdsa/marshal_test.go similarity index 100% rename from ecc/bls12-381/ecdsa/marshal_test.go rename to ecc/bls12-381/signature/ecdsa/marshal_test.go diff --git a/ecc/bls24-315/ecdsa/doc.go b/ecc/bls24-315/signature/ecdsa/doc.go similarity index 100% rename from ecc/bls24-315/ecdsa/doc.go rename to ecc/bls24-315/signature/ecdsa/doc.go diff --git a/ecc/bls24-315/ecdsa/ecdsa.go b/ecc/bls24-315/signature/ecdsa/ecdsa.go similarity index 100% rename from ecc/bls24-315/ecdsa/ecdsa.go rename to ecc/bls24-315/signature/ecdsa/ecdsa.go diff --git a/ecc/bls24-315/ecdsa/ecdsa_test.go b/ecc/bls24-315/signature/ecdsa/ecdsa_test.go similarity index 100% rename from ecc/bls24-315/ecdsa/ecdsa_test.go rename to ecc/bls24-315/signature/ecdsa/ecdsa_test.go diff --git a/ecc/bls24-315/ecdsa/marshal.go b/ecc/bls24-315/signature/ecdsa/marshal.go similarity index 100% rename from ecc/bls24-315/ecdsa/marshal.go rename to ecc/bls24-315/signature/ecdsa/marshal.go diff --git a/ecc/bls24-315/ecdsa/marshal_test.go b/ecc/bls24-315/signature/ecdsa/marshal_test.go similarity index 100% rename from ecc/bls24-315/ecdsa/marshal_test.go rename to ecc/bls24-315/signature/ecdsa/marshal_test.go diff --git a/ecc/bls24-317/ecdsa/doc.go b/ecc/bls24-317/signature/ecdsa/doc.go similarity index 100% rename from ecc/bls24-317/ecdsa/doc.go rename to ecc/bls24-317/signature/ecdsa/doc.go diff --git a/ecc/bls24-317/ecdsa/ecdsa.go b/ecc/bls24-317/signature/ecdsa/ecdsa.go similarity index 100% rename from ecc/bls24-317/ecdsa/ecdsa.go rename to ecc/bls24-317/signature/ecdsa/ecdsa.go diff --git a/ecc/bls24-317/ecdsa/ecdsa_test.go b/ecc/bls24-317/signature/ecdsa/ecdsa_test.go similarity index 100% rename from ecc/bls24-317/ecdsa/ecdsa_test.go rename to ecc/bls24-317/signature/ecdsa/ecdsa_test.go diff --git a/ecc/bls24-317/ecdsa/marshal.go b/ecc/bls24-317/signature/ecdsa/marshal.go similarity index 100% rename from ecc/bls24-317/ecdsa/marshal.go rename to ecc/bls24-317/signature/ecdsa/marshal.go diff --git a/ecc/bls24-317/ecdsa/marshal_test.go b/ecc/bls24-317/signature/ecdsa/marshal_test.go similarity index 100% rename from ecc/bls24-317/ecdsa/marshal_test.go rename to ecc/bls24-317/signature/ecdsa/marshal_test.go diff --git a/ecc/bn254/ecdsa/doc.go b/ecc/bn254/signature/ecdsa/doc.go similarity index 100% rename from ecc/bn254/ecdsa/doc.go rename to ecc/bn254/signature/ecdsa/doc.go diff --git a/ecc/bn254/ecdsa/ecdsa.go b/ecc/bn254/signature/ecdsa/ecdsa.go similarity index 100% rename from ecc/bn254/ecdsa/ecdsa.go rename to ecc/bn254/signature/ecdsa/ecdsa.go diff --git a/ecc/bn254/ecdsa/ecdsa_test.go b/ecc/bn254/signature/ecdsa/ecdsa_test.go similarity index 100% rename from ecc/bn254/ecdsa/ecdsa_test.go rename to ecc/bn254/signature/ecdsa/ecdsa_test.go diff --git a/ecc/bn254/ecdsa/marshal.go b/ecc/bn254/signature/ecdsa/marshal.go similarity index 100% rename from ecc/bn254/ecdsa/marshal.go rename to ecc/bn254/signature/ecdsa/marshal.go diff --git a/ecc/bn254/ecdsa/marshal_test.go b/ecc/bn254/signature/ecdsa/marshal_test.go similarity index 100% rename from ecc/bn254/ecdsa/marshal_test.go rename to ecc/bn254/signature/ecdsa/marshal_test.go diff --git a/ecc/bw6-633/ecdsa/doc.go b/ecc/bw6-633/signature/ecdsa/doc.go similarity index 100% rename from ecc/bw6-633/ecdsa/doc.go rename to ecc/bw6-633/signature/ecdsa/doc.go diff --git a/ecc/bw6-633/ecdsa/ecdsa.go b/ecc/bw6-633/signature/ecdsa/ecdsa.go similarity index 100% rename from ecc/bw6-633/ecdsa/ecdsa.go rename to ecc/bw6-633/signature/ecdsa/ecdsa.go diff --git a/ecc/bw6-633/ecdsa/ecdsa_test.go b/ecc/bw6-633/signature/ecdsa/ecdsa_test.go similarity index 100% rename from ecc/bw6-633/ecdsa/ecdsa_test.go rename to ecc/bw6-633/signature/ecdsa/ecdsa_test.go diff --git a/ecc/bw6-633/ecdsa/marshal.go b/ecc/bw6-633/signature/ecdsa/marshal.go similarity index 100% rename from ecc/bw6-633/ecdsa/marshal.go rename to ecc/bw6-633/signature/ecdsa/marshal.go diff --git a/ecc/bw6-633/ecdsa/marshal_test.go b/ecc/bw6-633/signature/ecdsa/marshal_test.go similarity index 100% rename from ecc/bw6-633/ecdsa/marshal_test.go rename to ecc/bw6-633/signature/ecdsa/marshal_test.go diff --git a/ecc/bw6-756/ecdsa/doc.go b/ecc/bw6-756/signature/ecdsa/doc.go similarity index 100% rename from ecc/bw6-756/ecdsa/doc.go rename to ecc/bw6-756/signature/ecdsa/doc.go diff --git a/ecc/bw6-756/ecdsa/ecdsa.go b/ecc/bw6-756/signature/ecdsa/ecdsa.go similarity index 100% rename from ecc/bw6-756/ecdsa/ecdsa.go rename to ecc/bw6-756/signature/ecdsa/ecdsa.go diff --git a/ecc/bw6-756/ecdsa/ecdsa_test.go b/ecc/bw6-756/signature/ecdsa/ecdsa_test.go similarity index 100% rename from ecc/bw6-756/ecdsa/ecdsa_test.go rename to ecc/bw6-756/signature/ecdsa/ecdsa_test.go diff --git a/ecc/bw6-756/ecdsa/marshal.go b/ecc/bw6-756/signature/ecdsa/marshal.go similarity index 100% rename from ecc/bw6-756/ecdsa/marshal.go rename to ecc/bw6-756/signature/ecdsa/marshal.go diff --git a/ecc/bw6-756/ecdsa/marshal_test.go b/ecc/bw6-756/signature/ecdsa/marshal_test.go similarity index 100% rename from ecc/bw6-756/ecdsa/marshal_test.go rename to ecc/bw6-756/signature/ecdsa/marshal_test.go diff --git a/ecc/bw6-761/ecdsa/doc.go b/ecc/bw6-761/signature/ecdsa/doc.go similarity index 100% rename from ecc/bw6-761/ecdsa/doc.go rename to ecc/bw6-761/signature/ecdsa/doc.go diff --git a/ecc/bw6-761/ecdsa/ecdsa.go b/ecc/bw6-761/signature/ecdsa/ecdsa.go similarity index 100% rename from ecc/bw6-761/ecdsa/ecdsa.go rename to ecc/bw6-761/signature/ecdsa/ecdsa.go diff --git a/ecc/bw6-761/ecdsa/ecdsa_test.go b/ecc/bw6-761/signature/ecdsa/ecdsa_test.go similarity index 100% rename from ecc/bw6-761/ecdsa/ecdsa_test.go rename to ecc/bw6-761/signature/ecdsa/ecdsa_test.go diff --git a/ecc/bw6-761/ecdsa/marshal.go b/ecc/bw6-761/signature/ecdsa/marshal.go similarity index 100% rename from ecc/bw6-761/ecdsa/marshal.go rename to ecc/bw6-761/signature/ecdsa/marshal.go diff --git a/ecc/bw6-761/ecdsa/marshal_test.go b/ecc/bw6-761/signature/ecdsa/marshal_test.go similarity index 100% rename from ecc/bw6-761/ecdsa/marshal_test.go rename to ecc/bw6-761/signature/ecdsa/marshal_test.go diff --git a/ecc/secp256k1/ecdsa/doc.go b/ecc/secp256k1/signature/ecdsa/doc.go similarity index 100% rename from ecc/secp256k1/ecdsa/doc.go rename to ecc/secp256k1/signature/ecdsa/doc.go diff --git a/ecc/secp256k1/ecdsa/ecdsa.go b/ecc/secp256k1/signature/ecdsa/ecdsa.go similarity index 100% rename from ecc/secp256k1/ecdsa/ecdsa.go rename to ecc/secp256k1/signature/ecdsa/ecdsa.go diff --git a/ecc/secp256k1/ecdsa/ecdsa_test.go b/ecc/secp256k1/signature/ecdsa/ecdsa_test.go similarity index 100% rename from ecc/secp256k1/ecdsa/ecdsa_test.go rename to ecc/secp256k1/signature/ecdsa/ecdsa_test.go diff --git a/ecc/secp256k1/ecdsa/marshal.go b/ecc/secp256k1/signature/ecdsa/marshal.go similarity index 100% rename from ecc/secp256k1/ecdsa/marshal.go rename to ecc/secp256k1/signature/ecdsa/marshal.go diff --git a/ecc/secp256k1/ecdsa/marshal_test.go b/ecc/secp256k1/signature/ecdsa/marshal_test.go similarity index 100% rename from ecc/secp256k1/ecdsa/marshal_test.go rename to ecc/secp256k1/signature/ecdsa/marshal_test.go diff --git a/ecc/stark-curve/ecdsa/doc.go b/ecc/stark-curve/signature/ecdsa/doc.go similarity index 100% rename from ecc/stark-curve/ecdsa/doc.go rename to ecc/stark-curve/signature/ecdsa/doc.go diff --git a/ecc/stark-curve/ecdsa/ecdsa.go b/ecc/stark-curve/signature/ecdsa/ecdsa.go similarity index 100% rename from ecc/stark-curve/ecdsa/ecdsa.go rename to ecc/stark-curve/signature/ecdsa/ecdsa.go diff --git a/ecc/stark-curve/ecdsa/ecdsa_test.go b/ecc/stark-curve/signature/ecdsa/ecdsa_test.go similarity index 100% rename from ecc/stark-curve/ecdsa/ecdsa_test.go rename to ecc/stark-curve/signature/ecdsa/ecdsa_test.go diff --git a/ecc/stark-curve/ecdsa/marshal.go b/ecc/stark-curve/signature/ecdsa/marshal.go similarity index 100% rename from ecc/stark-curve/ecdsa/marshal.go rename to ecc/stark-curve/signature/ecdsa/marshal.go diff --git a/ecc/stark-curve/ecdsa/marshal_test.go b/ecc/stark-curve/signature/ecdsa/marshal_test.go similarity index 100% rename from ecc/stark-curve/ecdsa/marshal_test.go rename to ecc/stark-curve/signature/ecdsa/marshal_test.go diff --git a/internal/generator/main.go b/internal/generator/main.go index 23f7b8ba6..ba2dd97c1 100644 --- a/internal/generator/main.go +++ b/internal/generator/main.go @@ -13,7 +13,6 @@ import ( "github.com/consensys/gnark-crypto/internal/generator/config" "github.com/consensys/gnark-crypto/internal/generator/crypto/hash/mimc" "github.com/consensys/gnark-crypto/internal/generator/ecc" - "github.com/consensys/gnark-crypto/internal/generator/ecdsa" "github.com/consensys/gnark-crypto/internal/generator/edwards" "github.com/consensys/gnark-crypto/internal/generator/edwards/eddsa" "github.com/consensys/gnark-crypto/internal/generator/fft" @@ -25,6 +24,7 @@ import ( "github.com/consensys/gnark-crypto/internal/generator/permutation" "github.com/consensys/gnark-crypto/internal/generator/plookup" "github.com/consensys/gnark-crypto/internal/generator/polynomial" + "github.com/consensys/gnark-crypto/internal/generator/signature/ecdsa" "github.com/consensys/gnark-crypto/internal/generator/sumcheck" "github.com/consensys/gnark-crypto/internal/generator/test_vector_utils" "github.com/consensys/gnark-crypto/internal/generator/tower" @@ -69,7 +69,7 @@ func main() { } // generate ecdsa - assertNoError(ecdsa.Generate(conf, curveDir, bgen)) + assertNoError(ecdsa.Generate(conf, filepath.Join(curveDir, "signature"), bgen)) if conf.Equal(config.STARK_CURVE) { return // TODO @yelhousni diff --git a/internal/generator/ecdsa/generate.go b/internal/generator/signature/ecdsa/generate.go similarity index 90% rename from internal/generator/ecdsa/generate.go rename to internal/generator/signature/ecdsa/generate.go index 00076625e..98031d558 100644 --- a/internal/generator/ecdsa/generate.go +++ b/internal/generator/signature/ecdsa/generate.go @@ -19,6 +19,6 @@ func Generate(conf config.Curve, baseDir string, bgen *bavard.BatchGenerator) er {File: filepath.Join(baseDir, "marshal.go"), Templates: []string{"marshal.go.tmpl"}}, {File: filepath.Join(baseDir, "marshal_test.go"), Templates: []string{"marshal.test.go.tmpl"}}, } - return bgen.Generate(conf, conf.Package, "./ecdsa/template", entries...) + return bgen.Generate(conf, conf.Package, "./signature/ecdsa/template", entries...) } diff --git a/internal/generator/ecdsa/template/doc.go.tmpl b/internal/generator/signature/ecdsa/template/doc.go.tmpl similarity index 100% rename from internal/generator/ecdsa/template/doc.go.tmpl rename to internal/generator/signature/ecdsa/template/doc.go.tmpl diff --git a/internal/generator/ecdsa/template/ecdsa.go.tmpl b/internal/generator/signature/ecdsa/template/ecdsa.go.tmpl similarity index 100% rename from internal/generator/ecdsa/template/ecdsa.go.tmpl rename to internal/generator/signature/ecdsa/template/ecdsa.go.tmpl diff --git a/internal/generator/ecdsa/template/ecdsa.test.go.tmpl b/internal/generator/signature/ecdsa/template/ecdsa.test.go.tmpl similarity index 100% rename from internal/generator/ecdsa/template/ecdsa.test.go.tmpl rename to internal/generator/signature/ecdsa/template/ecdsa.test.go.tmpl diff --git a/internal/generator/ecdsa/template/marshal.go.tmpl b/internal/generator/signature/ecdsa/template/marshal.go.tmpl similarity index 100% rename from internal/generator/ecdsa/template/marshal.go.tmpl rename to internal/generator/signature/ecdsa/template/marshal.go.tmpl diff --git a/internal/generator/ecdsa/template/marshal.test.go.tmpl b/internal/generator/signature/ecdsa/template/marshal.test.go.tmpl similarity index 100% rename from internal/generator/ecdsa/template/marshal.test.go.tmpl rename to internal/generator/signature/ecdsa/template/marshal.test.go.tmpl From dcecc4c3f21b9418cc291775b9a8e61e67a4e292 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 25 Jan 2023 17:11:59 +0100 Subject: [PATCH 2/7] feat: add schnorr signature on all curves --- ecc/bls12-377/signature/schnorr/doc.go | 23 ++ ecc/bls12-377/signature/schnorr/marshal.go | 108 +++++++ .../signature/schnorr/marshal_test.go | 64 ++++ ecc/bls12-377/signature/schnorr/schnorr.go | 278 ++++++++++++++++++ .../signature/schnorr/schnorr_test.go | 78 +++++ ecc/bls12-378/signature/schnorr/doc.go | 23 ++ ecc/bls12-378/signature/schnorr/marshal.go | 108 +++++++ .../signature/schnorr/marshal_test.go | 64 ++++ ecc/bls12-378/signature/schnorr/schnorr.go | 278 ++++++++++++++++++ .../signature/schnorr/schnorr_test.go | 78 +++++ ecc/bls12-381/signature/schnorr/doc.go | 23 ++ ecc/bls12-381/signature/schnorr/marshal.go | 108 +++++++ .../signature/schnorr/marshal_test.go | 64 ++++ ecc/bls12-381/signature/schnorr/schnorr.go | 278 ++++++++++++++++++ .../signature/schnorr/schnorr_test.go | 78 +++++ ecc/bls24-315/signature/schnorr/doc.go | 23 ++ ecc/bls24-315/signature/schnorr/marshal.go | 108 +++++++ .../signature/schnorr/marshal_test.go | 64 ++++ ecc/bls24-315/signature/schnorr/schnorr.go | 278 ++++++++++++++++++ .../signature/schnorr/schnorr_test.go | 78 +++++ ecc/bls24-317/signature/schnorr/doc.go | 23 ++ ecc/bls24-317/signature/schnorr/marshal.go | 108 +++++++ .../signature/schnorr/marshal_test.go | 64 ++++ ecc/bls24-317/signature/schnorr/schnorr.go | 278 ++++++++++++++++++ .../signature/schnorr/schnorr_test.go | 78 +++++ ecc/bn254/signature/schnorr/doc.go | 23 ++ ecc/bn254/signature/schnorr/marshal.go | 108 +++++++ ecc/bn254/signature/schnorr/marshal_test.go | 64 ++++ ecc/bn254/signature/schnorr/schnorr.go | 278 ++++++++++++++++++ ecc/bn254/signature/schnorr/schnorr_test.go | 78 +++++ ecc/bw6-633/signature/schnorr/doc.go | 23 ++ ecc/bw6-633/signature/schnorr/marshal.go | 108 +++++++ ecc/bw6-633/signature/schnorr/marshal_test.go | 64 ++++ ecc/bw6-633/signature/schnorr/schnorr.go | 278 ++++++++++++++++++ ecc/bw6-633/signature/schnorr/schnorr_test.go | 78 +++++ ecc/bw6-756/signature/schnorr/doc.go | 23 ++ ecc/bw6-756/signature/schnorr/marshal.go | 108 +++++++ ecc/bw6-756/signature/schnorr/marshal_test.go | 64 ++++ ecc/bw6-756/signature/schnorr/schnorr.go | 278 ++++++++++++++++++ ecc/bw6-756/signature/schnorr/schnorr_test.go | 78 +++++ ecc/bw6-761/signature/schnorr/doc.go | 23 ++ ecc/bw6-761/signature/schnorr/marshal.go | 108 +++++++ ecc/bw6-761/signature/schnorr/marshal_test.go | 64 ++++ ecc/bw6-761/signature/schnorr/schnorr.go | 278 ++++++++++++++++++ ecc/bw6-761/signature/schnorr/schnorr_test.go | 78 +++++ ecc/secp256k1/signature/schnorr/doc.go | 23 ++ ecc/secp256k1/signature/schnorr/marshal.go | 108 +++++++ .../signature/schnorr/marshal_test.go | 64 ++++ ecc/secp256k1/signature/schnorr/schnorr.go | 278 ++++++++++++++++++ .../signature/schnorr/schnorr_test.go | 78 +++++ ecc/stark-curve/signature/schnorr/doc.go | 23 ++ ecc/stark-curve/signature/schnorr/marshal.go | 108 +++++++ .../signature/schnorr/marshal_test.go | 64 ++++ ecc/stark-curve/signature/schnorr/schnorr.go | 278 ++++++++++++++++++ .../signature/schnorr/schnorr_test.go | 78 +++++ internal/generator/main.go | 6 +- .../generator/signature/schnorr/generate.go | 24 ++ .../signature/schnorr/template/doc.go.tmpl | 8 + .../schnorr/template/marshal.go.tmpl | 98 ++++++ .../schnorr/template/marshal.test.go.tmpl | 46 +++ .../schnorr/template/schnorr.go.tmpl | 269 +++++++++++++++++ .../schnorr/template/schnorr.test.go.tmpl | 60 ++++ signature/ecdsa/ecdsa.go | 22 +- signature/schnorr/schnorr.go | 65 ++++ 64 files changed, 6647 insertions(+), 12 deletions(-) create mode 100644 ecc/bls12-377/signature/schnorr/doc.go create mode 100644 ecc/bls12-377/signature/schnorr/marshal.go create mode 100644 ecc/bls12-377/signature/schnorr/marshal_test.go create mode 100644 ecc/bls12-377/signature/schnorr/schnorr.go create mode 100644 ecc/bls12-377/signature/schnorr/schnorr_test.go create mode 100644 ecc/bls12-378/signature/schnorr/doc.go create mode 100644 ecc/bls12-378/signature/schnorr/marshal.go create mode 100644 ecc/bls12-378/signature/schnorr/marshal_test.go create mode 100644 ecc/bls12-378/signature/schnorr/schnorr.go create mode 100644 ecc/bls12-378/signature/schnorr/schnorr_test.go create mode 100644 ecc/bls12-381/signature/schnorr/doc.go create mode 100644 ecc/bls12-381/signature/schnorr/marshal.go create mode 100644 ecc/bls12-381/signature/schnorr/marshal_test.go create mode 100644 ecc/bls12-381/signature/schnorr/schnorr.go create mode 100644 ecc/bls12-381/signature/schnorr/schnorr_test.go create mode 100644 ecc/bls24-315/signature/schnorr/doc.go create mode 100644 ecc/bls24-315/signature/schnorr/marshal.go create mode 100644 ecc/bls24-315/signature/schnorr/marshal_test.go create mode 100644 ecc/bls24-315/signature/schnorr/schnorr.go create mode 100644 ecc/bls24-315/signature/schnorr/schnorr_test.go create mode 100644 ecc/bls24-317/signature/schnorr/doc.go create mode 100644 ecc/bls24-317/signature/schnorr/marshal.go create mode 100644 ecc/bls24-317/signature/schnorr/marshal_test.go create mode 100644 ecc/bls24-317/signature/schnorr/schnorr.go create mode 100644 ecc/bls24-317/signature/schnorr/schnorr_test.go create mode 100644 ecc/bn254/signature/schnorr/doc.go create mode 100644 ecc/bn254/signature/schnorr/marshal.go create mode 100644 ecc/bn254/signature/schnorr/marshal_test.go create mode 100644 ecc/bn254/signature/schnorr/schnorr.go create mode 100644 ecc/bn254/signature/schnorr/schnorr_test.go create mode 100644 ecc/bw6-633/signature/schnorr/doc.go create mode 100644 ecc/bw6-633/signature/schnorr/marshal.go create mode 100644 ecc/bw6-633/signature/schnorr/marshal_test.go create mode 100644 ecc/bw6-633/signature/schnorr/schnorr.go create mode 100644 ecc/bw6-633/signature/schnorr/schnorr_test.go create mode 100644 ecc/bw6-756/signature/schnorr/doc.go create mode 100644 ecc/bw6-756/signature/schnorr/marshal.go create mode 100644 ecc/bw6-756/signature/schnorr/marshal_test.go create mode 100644 ecc/bw6-756/signature/schnorr/schnorr.go create mode 100644 ecc/bw6-756/signature/schnorr/schnorr_test.go create mode 100644 ecc/bw6-761/signature/schnorr/doc.go create mode 100644 ecc/bw6-761/signature/schnorr/marshal.go create mode 100644 ecc/bw6-761/signature/schnorr/marshal_test.go create mode 100644 ecc/bw6-761/signature/schnorr/schnorr.go create mode 100644 ecc/bw6-761/signature/schnorr/schnorr_test.go create mode 100644 ecc/secp256k1/signature/schnorr/doc.go create mode 100644 ecc/secp256k1/signature/schnorr/marshal.go create mode 100644 ecc/secp256k1/signature/schnorr/marshal_test.go create mode 100644 ecc/secp256k1/signature/schnorr/schnorr.go create mode 100644 ecc/secp256k1/signature/schnorr/schnorr_test.go create mode 100644 ecc/stark-curve/signature/schnorr/doc.go create mode 100644 ecc/stark-curve/signature/schnorr/marshal.go create mode 100644 ecc/stark-curve/signature/schnorr/marshal_test.go create mode 100644 ecc/stark-curve/signature/schnorr/schnorr.go create mode 100644 ecc/stark-curve/signature/schnorr/schnorr_test.go create mode 100644 internal/generator/signature/schnorr/generate.go create mode 100644 internal/generator/signature/schnorr/template/doc.go.tmpl create mode 100644 internal/generator/signature/schnorr/template/marshal.go.tmpl create mode 100644 internal/generator/signature/schnorr/template/marshal.test.go.tmpl create mode 100644 internal/generator/signature/schnorr/template/schnorr.go.tmpl create mode 100644 internal/generator/signature/schnorr/template/schnorr.test.go.tmpl create mode 100644 signature/schnorr/schnorr.go diff --git a/ecc/bls12-377/signature/schnorr/doc.go b/ecc/bls12-377/signature/schnorr/doc.go new file mode 100644 index 000000000..5d1c86957 --- /dev/null +++ b/ecc/bls12-377/signature/schnorr/doc.go @@ -0,0 +1,23 @@ +// 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 schnorr provides Schnorr signature scheme on the bls12-377 curve. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Schnorr_signature +// - RFC8235: https://www.rfc-editor.org/rfc/rfc8235 +// - BIP-340: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki +package schnorr diff --git a/ecc/bls12-377/signature/schnorr/marshal.go b/ecc/bls12-377/signature/schnorr/marshal.go new file mode 100644 index 000000000..2b92ad686 --- /dev/null +++ b/ecc/bls12-377/signature/schnorr/marshal.go @@ -0,0 +1,108 @@ +// 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 schnorr + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/ecc/bls12-377/signature/schnorr/marshal_test.go b/ecc/bls12-377/signature/schnorr/marshal_test.go new file mode 100644 index 000000000..5bd24a7e5 --- /dev/null +++ b/ecc/bls12-377/signature/schnorr/marshal_test.go @@ -0,0 +1,64 @@ +// 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 schnorr + +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[BLS12-377] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bls12-377/signature/schnorr/schnorr.go b/ecc/bls12-377/signature/schnorr/schnorr.go new file mode 100644 index 000000000..70a485c22 --- /dev/null +++ b/ecc/bls12-377/signature/schnorr/schnorr.go @@ -0,0 +1,278 @@ +// 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 schnorr + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/sha512" + "crypto/subtle" + "errors" + "hash" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bls12-377" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/signature" +) + +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes + sizePublicKey = sizeFp + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + +// PublicKey represents an Schnorr public key +type PublicKey struct { + A bls12377.G1Affine +} + +// PrivateKey represents an Schnorr private key +type PrivateKey struct { + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian +} + +// Signature represents an Schnorr signature +type Signature struct { + R, S [sizeFr]byte +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func randFieldElement(rand io.Reader) (k *big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(order, one) + k.Mod(k, n) + k.Add(k, one) + return +} + +// GenerateKey generates a public and private key pair. +func GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := randFieldElement(rand) + if err != nil { + return nil, err + + } + _, _, g, _ := bls12377.Generators() + + privateKey := new(PrivateKey) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) + return privateKey, nil +} + +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func HashToInt(hash []byte) *big.Int { + if len(hash) > sizeFr { + hash = hash[:sizeFr] + } + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - sizeFr + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand.Reader, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + +// Sign performs the Schnorr signature +// +// k ← 𝔽r (random) +// P = k ⋅ g1Gen +// r = H ( P || m ) +// s = k - x ⋅ r +// signature = {r, s} +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) + csprng, err := nonce(privKey, message) + if err != nil { + return nil, err + } + k, err := randFieldElement(csprng) + if err != nil { + return nil, err + } + + var P bls12377.G1Affine + P.ScalarMultiplicationBase(k) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + + s.Mul(scalar, r) + s.Sub(k, s). + Mod(s, order) + + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) + + return sig.Bytes(), nil +} + +// Verify validates the Schnorr signature +// +// R = s ⋅ Base + r ⋅ publiKey +// H ( R || m ) ?= r +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err + } + + r, s, e := new(big.Int), new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + var P bls12377.G1Jac + P.JointScalarMultiplicationBase(&publicKey.A, s, r) + var _P bls12377.G1Affine + _P.FromJacobian(&P) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + + return e.Cmp(r) == 0, nil + +} diff --git a/ecc/bls12-377/signature/schnorr/schnorr_test.go b/ecc/bls12-377/signature/schnorr/schnorr_test.go new file mode 100644 index 000000000..68b7c8c57 --- /dev/null +++ b/ecc/bls12-377/signature/schnorr/schnorr_test.go @@ -0,0 +1,78 @@ +// 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 schnorr + +import ( + "crypto/rand" + "crypto/sha256" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestSchnorr(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[BLS12-377] test the signing and verification", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + flag, _ := publicKey.Verify(sig, msg, hFunc) + + return flag + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignSchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.Sign(msg, hFunc) + } +} + +func BenchmarkVerifySchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.PublicKey.Verify(sig, msg, hFunc) + } +} diff --git a/ecc/bls12-378/signature/schnorr/doc.go b/ecc/bls12-378/signature/schnorr/doc.go new file mode 100644 index 000000000..6d056ac70 --- /dev/null +++ b/ecc/bls12-378/signature/schnorr/doc.go @@ -0,0 +1,23 @@ +// 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 schnorr provides Schnorr signature scheme on the bls12-378 curve. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Schnorr_signature +// - RFC8235: https://www.rfc-editor.org/rfc/rfc8235 +// - BIP-340: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki +package schnorr diff --git a/ecc/bls12-378/signature/schnorr/marshal.go b/ecc/bls12-378/signature/schnorr/marshal.go new file mode 100644 index 000000000..2b92ad686 --- /dev/null +++ b/ecc/bls12-378/signature/schnorr/marshal.go @@ -0,0 +1,108 @@ +// 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 schnorr + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/ecc/bls12-378/signature/schnorr/marshal_test.go b/ecc/bls12-378/signature/schnorr/marshal_test.go new file mode 100644 index 000000000..3c81b214c --- /dev/null +++ b/ecc/bls12-378/signature/schnorr/marshal_test.go @@ -0,0 +1,64 @@ +// 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 schnorr + +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[BLS12-378] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bls12-378/signature/schnorr/schnorr.go b/ecc/bls12-378/signature/schnorr/schnorr.go new file mode 100644 index 000000000..e7277a5ef --- /dev/null +++ b/ecc/bls12-378/signature/schnorr/schnorr.go @@ -0,0 +1,278 @@ +// 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 schnorr + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/sha512" + "crypto/subtle" + "errors" + "hash" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bls12-378" + "github.com/consensys/gnark-crypto/ecc/bls12-378/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-378/fr" + "github.com/consensys/gnark-crypto/signature" +) + +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes + sizePublicKey = sizeFp + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + +// PublicKey represents an Schnorr public key +type PublicKey struct { + A bls12378.G1Affine +} + +// PrivateKey represents an Schnorr private key +type PrivateKey struct { + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian +} + +// Signature represents an Schnorr signature +type Signature struct { + R, S [sizeFr]byte +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func randFieldElement(rand io.Reader) (k *big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(order, one) + k.Mod(k, n) + k.Add(k, one) + return +} + +// GenerateKey generates a public and private key pair. +func GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := randFieldElement(rand) + if err != nil { + return nil, err + + } + _, _, g, _ := bls12378.Generators() + + privateKey := new(PrivateKey) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) + return privateKey, nil +} + +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func HashToInt(hash []byte) *big.Int { + if len(hash) > sizeFr { + hash = hash[:sizeFr] + } + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - sizeFr + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand.Reader, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + +// Sign performs the Schnorr signature +// +// k ← 𝔽r (random) +// P = k ⋅ g1Gen +// r = H ( P || m ) +// s = k - x ⋅ r +// signature = {r, s} +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) + csprng, err := nonce(privKey, message) + if err != nil { + return nil, err + } + k, err := randFieldElement(csprng) + if err != nil { + return nil, err + } + + var P bls12378.G1Affine + P.ScalarMultiplicationBase(k) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + + s.Mul(scalar, r) + s.Sub(k, s). + Mod(s, order) + + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) + + return sig.Bytes(), nil +} + +// Verify validates the Schnorr signature +// +// R = s ⋅ Base + r ⋅ publiKey +// H ( R || m ) ?= r +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err + } + + r, s, e := new(big.Int), new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + var P bls12378.G1Jac + P.JointScalarMultiplicationBase(&publicKey.A, s, r) + var _P bls12378.G1Affine + _P.FromJacobian(&P) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + + return e.Cmp(r) == 0, nil + +} diff --git a/ecc/bls12-378/signature/schnorr/schnorr_test.go b/ecc/bls12-378/signature/schnorr/schnorr_test.go new file mode 100644 index 000000000..69d54ce8f --- /dev/null +++ b/ecc/bls12-378/signature/schnorr/schnorr_test.go @@ -0,0 +1,78 @@ +// 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 schnorr + +import ( + "crypto/rand" + "crypto/sha256" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestSchnorr(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[BLS12-378] test the signing and verification", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + flag, _ := publicKey.Verify(sig, msg, hFunc) + + return flag + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignSchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.Sign(msg, hFunc) + } +} + +func BenchmarkVerifySchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.PublicKey.Verify(sig, msg, hFunc) + } +} diff --git a/ecc/bls12-381/signature/schnorr/doc.go b/ecc/bls12-381/signature/schnorr/doc.go new file mode 100644 index 000000000..dcf3bb586 --- /dev/null +++ b/ecc/bls12-381/signature/schnorr/doc.go @@ -0,0 +1,23 @@ +// 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 schnorr provides Schnorr signature scheme on the bls12-381 curve. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Schnorr_signature +// - RFC8235: https://www.rfc-editor.org/rfc/rfc8235 +// - BIP-340: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki +package schnorr diff --git a/ecc/bls12-381/signature/schnorr/marshal.go b/ecc/bls12-381/signature/schnorr/marshal.go new file mode 100644 index 000000000..2b92ad686 --- /dev/null +++ b/ecc/bls12-381/signature/schnorr/marshal.go @@ -0,0 +1,108 @@ +// 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 schnorr + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/ecc/bls12-381/signature/schnorr/marshal_test.go b/ecc/bls12-381/signature/schnorr/marshal_test.go new file mode 100644 index 000000000..df30517a8 --- /dev/null +++ b/ecc/bls12-381/signature/schnorr/marshal_test.go @@ -0,0 +1,64 @@ +// 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 schnorr + +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[BLS12-381] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bls12-381/signature/schnorr/schnorr.go b/ecc/bls12-381/signature/schnorr/schnorr.go new file mode 100644 index 000000000..60ebbdfd1 --- /dev/null +++ b/ecc/bls12-381/signature/schnorr/schnorr.go @@ -0,0 +1,278 @@ +// 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 schnorr + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/sha512" + "crypto/subtle" + "errors" + "hash" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/consensys/gnark-crypto/signature" +) + +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes + sizePublicKey = sizeFp + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + +// PublicKey represents an Schnorr public key +type PublicKey struct { + A bls12381.G1Affine +} + +// PrivateKey represents an Schnorr private key +type PrivateKey struct { + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian +} + +// Signature represents an Schnorr signature +type Signature struct { + R, S [sizeFr]byte +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func randFieldElement(rand io.Reader) (k *big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(order, one) + k.Mod(k, n) + k.Add(k, one) + return +} + +// GenerateKey generates a public and private key pair. +func GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := randFieldElement(rand) + if err != nil { + return nil, err + + } + _, _, g, _ := bls12381.Generators() + + privateKey := new(PrivateKey) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) + return privateKey, nil +} + +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func HashToInt(hash []byte) *big.Int { + if len(hash) > sizeFr { + hash = hash[:sizeFr] + } + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - sizeFr + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand.Reader, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + +// Sign performs the Schnorr signature +// +// k ← 𝔽r (random) +// P = k ⋅ g1Gen +// r = H ( P || m ) +// s = k - x ⋅ r +// signature = {r, s} +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) + csprng, err := nonce(privKey, message) + if err != nil { + return nil, err + } + k, err := randFieldElement(csprng) + if err != nil { + return nil, err + } + + var P bls12381.G1Affine + P.ScalarMultiplicationBase(k) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + + s.Mul(scalar, r) + s.Sub(k, s). + Mod(s, order) + + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) + + return sig.Bytes(), nil +} + +// Verify validates the Schnorr signature +// +// R = s ⋅ Base + r ⋅ publiKey +// H ( R || m ) ?= r +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err + } + + r, s, e := new(big.Int), new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + var P bls12381.G1Jac + P.JointScalarMultiplicationBase(&publicKey.A, s, r) + var _P bls12381.G1Affine + _P.FromJacobian(&P) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + + return e.Cmp(r) == 0, nil + +} diff --git a/ecc/bls12-381/signature/schnorr/schnorr_test.go b/ecc/bls12-381/signature/schnorr/schnorr_test.go new file mode 100644 index 000000000..ca692100c --- /dev/null +++ b/ecc/bls12-381/signature/schnorr/schnorr_test.go @@ -0,0 +1,78 @@ +// 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 schnorr + +import ( + "crypto/rand" + "crypto/sha256" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestSchnorr(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[BLS12-381] test the signing and verification", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + flag, _ := publicKey.Verify(sig, msg, hFunc) + + return flag + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignSchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.Sign(msg, hFunc) + } +} + +func BenchmarkVerifySchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.PublicKey.Verify(sig, msg, hFunc) + } +} diff --git a/ecc/bls24-315/signature/schnorr/doc.go b/ecc/bls24-315/signature/schnorr/doc.go new file mode 100644 index 000000000..ff4bf0324 --- /dev/null +++ b/ecc/bls24-315/signature/schnorr/doc.go @@ -0,0 +1,23 @@ +// 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 schnorr provides Schnorr signature scheme on the bls24-315 curve. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Schnorr_signature +// - RFC8235: https://www.rfc-editor.org/rfc/rfc8235 +// - BIP-340: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki +package schnorr diff --git a/ecc/bls24-315/signature/schnorr/marshal.go b/ecc/bls24-315/signature/schnorr/marshal.go new file mode 100644 index 000000000..2b92ad686 --- /dev/null +++ b/ecc/bls24-315/signature/schnorr/marshal.go @@ -0,0 +1,108 @@ +// 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 schnorr + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/ecc/bls24-315/signature/schnorr/marshal_test.go b/ecc/bls24-315/signature/schnorr/marshal_test.go new file mode 100644 index 000000000..43bcbeb6b --- /dev/null +++ b/ecc/bls24-315/signature/schnorr/marshal_test.go @@ -0,0 +1,64 @@ +// 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 schnorr + +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[BLS24-315] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bls24-315/signature/schnorr/schnorr.go b/ecc/bls24-315/signature/schnorr/schnorr.go new file mode 100644 index 000000000..7ebbc88e4 --- /dev/null +++ b/ecc/bls24-315/signature/schnorr/schnorr.go @@ -0,0 +1,278 @@ +// 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 schnorr + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/sha512" + "crypto/subtle" + "errors" + "hash" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bls24-315" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fp" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" + "github.com/consensys/gnark-crypto/signature" +) + +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes + sizePublicKey = sizeFp + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + +// PublicKey represents an Schnorr public key +type PublicKey struct { + A bls24315.G1Affine +} + +// PrivateKey represents an Schnorr private key +type PrivateKey struct { + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian +} + +// Signature represents an Schnorr signature +type Signature struct { + R, S [sizeFr]byte +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func randFieldElement(rand io.Reader) (k *big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(order, one) + k.Mod(k, n) + k.Add(k, one) + return +} + +// GenerateKey generates a public and private key pair. +func GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := randFieldElement(rand) + if err != nil { + return nil, err + + } + _, _, g, _ := bls24315.Generators() + + privateKey := new(PrivateKey) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) + return privateKey, nil +} + +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func HashToInt(hash []byte) *big.Int { + if len(hash) > sizeFr { + hash = hash[:sizeFr] + } + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - sizeFr + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand.Reader, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + +// Sign performs the Schnorr signature +// +// k ← 𝔽r (random) +// P = k ⋅ g1Gen +// r = H ( P || m ) +// s = k - x ⋅ r +// signature = {r, s} +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) + csprng, err := nonce(privKey, message) + if err != nil { + return nil, err + } + k, err := randFieldElement(csprng) + if err != nil { + return nil, err + } + + var P bls24315.G1Affine + P.ScalarMultiplicationBase(k) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + + s.Mul(scalar, r) + s.Sub(k, s). + Mod(s, order) + + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) + + return sig.Bytes(), nil +} + +// Verify validates the Schnorr signature +// +// R = s ⋅ Base + r ⋅ publiKey +// H ( R || m ) ?= r +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err + } + + r, s, e := new(big.Int), new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + var P bls24315.G1Jac + P.JointScalarMultiplicationBase(&publicKey.A, s, r) + var _P bls24315.G1Affine + _P.FromJacobian(&P) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + + return e.Cmp(r) == 0, nil + +} diff --git a/ecc/bls24-315/signature/schnorr/schnorr_test.go b/ecc/bls24-315/signature/schnorr/schnorr_test.go new file mode 100644 index 000000000..a36590b40 --- /dev/null +++ b/ecc/bls24-315/signature/schnorr/schnorr_test.go @@ -0,0 +1,78 @@ +// 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 schnorr + +import ( + "crypto/rand" + "crypto/sha256" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestSchnorr(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[BLS24-315] test the signing and verification", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + flag, _ := publicKey.Verify(sig, msg, hFunc) + + return flag + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignSchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.Sign(msg, hFunc) + } +} + +func BenchmarkVerifySchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.PublicKey.Verify(sig, msg, hFunc) + } +} diff --git a/ecc/bls24-317/signature/schnorr/doc.go b/ecc/bls24-317/signature/schnorr/doc.go new file mode 100644 index 000000000..12245de88 --- /dev/null +++ b/ecc/bls24-317/signature/schnorr/doc.go @@ -0,0 +1,23 @@ +// 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 schnorr provides Schnorr signature scheme on the bls24-317 curve. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Schnorr_signature +// - RFC8235: https://www.rfc-editor.org/rfc/rfc8235 +// - BIP-340: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki +package schnorr diff --git a/ecc/bls24-317/signature/schnorr/marshal.go b/ecc/bls24-317/signature/schnorr/marshal.go new file mode 100644 index 000000000..2b92ad686 --- /dev/null +++ b/ecc/bls24-317/signature/schnorr/marshal.go @@ -0,0 +1,108 @@ +// 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 schnorr + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/ecc/bls24-317/signature/schnorr/marshal_test.go b/ecc/bls24-317/signature/schnorr/marshal_test.go new file mode 100644 index 000000000..cf16dbb36 --- /dev/null +++ b/ecc/bls24-317/signature/schnorr/marshal_test.go @@ -0,0 +1,64 @@ +// 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 schnorr + +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[BLS24-317] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bls24-317/signature/schnorr/schnorr.go b/ecc/bls24-317/signature/schnorr/schnorr.go new file mode 100644 index 000000000..76f5bd465 --- /dev/null +++ b/ecc/bls24-317/signature/schnorr/schnorr.go @@ -0,0 +1,278 @@ +// 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 schnorr + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/sha512" + "crypto/subtle" + "errors" + "hash" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bls24-317" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fp" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" + "github.com/consensys/gnark-crypto/signature" +) + +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes + sizePublicKey = sizeFp + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + +// PublicKey represents an Schnorr public key +type PublicKey struct { + A bls24317.G1Affine +} + +// PrivateKey represents an Schnorr private key +type PrivateKey struct { + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian +} + +// Signature represents an Schnorr signature +type Signature struct { + R, S [sizeFr]byte +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func randFieldElement(rand io.Reader) (k *big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(order, one) + k.Mod(k, n) + k.Add(k, one) + return +} + +// GenerateKey generates a public and private key pair. +func GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := randFieldElement(rand) + if err != nil { + return nil, err + + } + _, _, g, _ := bls24317.Generators() + + privateKey := new(PrivateKey) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) + return privateKey, nil +} + +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func HashToInt(hash []byte) *big.Int { + if len(hash) > sizeFr { + hash = hash[:sizeFr] + } + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - sizeFr + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand.Reader, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + +// Sign performs the Schnorr signature +// +// k ← 𝔽r (random) +// P = k ⋅ g1Gen +// r = H ( P || m ) +// s = k - x ⋅ r +// signature = {r, s} +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) + csprng, err := nonce(privKey, message) + if err != nil { + return nil, err + } + k, err := randFieldElement(csprng) + if err != nil { + return nil, err + } + + var P bls24317.G1Affine + P.ScalarMultiplicationBase(k) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + + s.Mul(scalar, r) + s.Sub(k, s). + Mod(s, order) + + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) + + return sig.Bytes(), nil +} + +// Verify validates the Schnorr signature +// +// R = s ⋅ Base + r ⋅ publiKey +// H ( R || m ) ?= r +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err + } + + r, s, e := new(big.Int), new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + var P bls24317.G1Jac + P.JointScalarMultiplicationBase(&publicKey.A, s, r) + var _P bls24317.G1Affine + _P.FromJacobian(&P) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + + return e.Cmp(r) == 0, nil + +} diff --git a/ecc/bls24-317/signature/schnorr/schnorr_test.go b/ecc/bls24-317/signature/schnorr/schnorr_test.go new file mode 100644 index 000000000..49ec67942 --- /dev/null +++ b/ecc/bls24-317/signature/schnorr/schnorr_test.go @@ -0,0 +1,78 @@ +// 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 schnorr + +import ( + "crypto/rand" + "crypto/sha256" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestSchnorr(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[BLS24-317] test the signing and verification", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + flag, _ := publicKey.Verify(sig, msg, hFunc) + + return flag + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignSchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.Sign(msg, hFunc) + } +} + +func BenchmarkVerifySchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.PublicKey.Verify(sig, msg, hFunc) + } +} diff --git a/ecc/bn254/signature/schnorr/doc.go b/ecc/bn254/signature/schnorr/doc.go new file mode 100644 index 000000000..630879533 --- /dev/null +++ b/ecc/bn254/signature/schnorr/doc.go @@ -0,0 +1,23 @@ +// 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 schnorr provides Schnorr signature scheme on the bn254 curve. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Schnorr_signature +// - RFC8235: https://www.rfc-editor.org/rfc/rfc8235 +// - BIP-340: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki +package schnorr diff --git a/ecc/bn254/signature/schnorr/marshal.go b/ecc/bn254/signature/schnorr/marshal.go new file mode 100644 index 000000000..2b92ad686 --- /dev/null +++ b/ecc/bn254/signature/schnorr/marshal.go @@ -0,0 +1,108 @@ +// 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 schnorr + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/ecc/bn254/signature/schnorr/marshal_test.go b/ecc/bn254/signature/schnorr/marshal_test.go new file mode 100644 index 000000000..169c1697c --- /dev/null +++ b/ecc/bn254/signature/schnorr/marshal_test.go @@ -0,0 +1,64 @@ +// 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 schnorr + +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[BN254] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bn254/signature/schnorr/schnorr.go b/ecc/bn254/signature/schnorr/schnorr.go new file mode 100644 index 000000000..e16e62e7e --- /dev/null +++ b/ecc/bn254/signature/schnorr/schnorr.go @@ -0,0 +1,278 @@ +// 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 schnorr + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/sha512" + "crypto/subtle" + "errors" + "hash" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark-crypto/signature" +) + +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes + sizePublicKey = sizeFp + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + +// PublicKey represents an Schnorr public key +type PublicKey struct { + A bn254.G1Affine +} + +// PrivateKey represents an Schnorr private key +type PrivateKey struct { + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian +} + +// Signature represents an Schnorr signature +type Signature struct { + R, S [sizeFr]byte +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func randFieldElement(rand io.Reader) (k *big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(order, one) + k.Mod(k, n) + k.Add(k, one) + return +} + +// GenerateKey generates a public and private key pair. +func GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := randFieldElement(rand) + if err != nil { + return nil, err + + } + _, _, g, _ := bn254.Generators() + + privateKey := new(PrivateKey) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) + return privateKey, nil +} + +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func HashToInt(hash []byte) *big.Int { + if len(hash) > sizeFr { + hash = hash[:sizeFr] + } + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - sizeFr + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand.Reader, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + +// Sign performs the Schnorr signature +// +// k ← 𝔽r (random) +// P = k ⋅ g1Gen +// r = H ( P || m ) +// s = k - x ⋅ r +// signature = {r, s} +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) + csprng, err := nonce(privKey, message) + if err != nil { + return nil, err + } + k, err := randFieldElement(csprng) + if err != nil { + return nil, err + } + + var P bn254.G1Affine + P.ScalarMultiplicationBase(k) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + + s.Mul(scalar, r) + s.Sub(k, s). + Mod(s, order) + + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) + + return sig.Bytes(), nil +} + +// Verify validates the Schnorr signature +// +// R = s ⋅ Base + r ⋅ publiKey +// H ( R || m ) ?= r +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err + } + + r, s, e := new(big.Int), new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + var P bn254.G1Jac + P.JointScalarMultiplicationBase(&publicKey.A, s, r) + var _P bn254.G1Affine + _P.FromJacobian(&P) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + + return e.Cmp(r) == 0, nil + +} diff --git a/ecc/bn254/signature/schnorr/schnorr_test.go b/ecc/bn254/signature/schnorr/schnorr_test.go new file mode 100644 index 000000000..9e8496fc0 --- /dev/null +++ b/ecc/bn254/signature/schnorr/schnorr_test.go @@ -0,0 +1,78 @@ +// 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 schnorr + +import ( + "crypto/rand" + "crypto/sha256" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestSchnorr(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[BN254] test the signing and verification", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + flag, _ := publicKey.Verify(sig, msg, hFunc) + + return flag + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignSchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.Sign(msg, hFunc) + } +} + +func BenchmarkVerifySchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.PublicKey.Verify(sig, msg, hFunc) + } +} diff --git a/ecc/bw6-633/signature/schnorr/doc.go b/ecc/bw6-633/signature/schnorr/doc.go new file mode 100644 index 000000000..8688835c3 --- /dev/null +++ b/ecc/bw6-633/signature/schnorr/doc.go @@ -0,0 +1,23 @@ +// 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 schnorr provides Schnorr signature scheme on the bw6-633 curve. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Schnorr_signature +// - RFC8235: https://www.rfc-editor.org/rfc/rfc8235 +// - BIP-340: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki +package schnorr diff --git a/ecc/bw6-633/signature/schnorr/marshal.go b/ecc/bw6-633/signature/schnorr/marshal.go new file mode 100644 index 000000000..2b92ad686 --- /dev/null +++ b/ecc/bw6-633/signature/schnorr/marshal.go @@ -0,0 +1,108 @@ +// 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 schnorr + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/ecc/bw6-633/signature/schnorr/marshal_test.go b/ecc/bw6-633/signature/schnorr/marshal_test.go new file mode 100644 index 000000000..3314c79ec --- /dev/null +++ b/ecc/bw6-633/signature/schnorr/marshal_test.go @@ -0,0 +1,64 @@ +// 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 schnorr + +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[BW6-633] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bw6-633/signature/schnorr/schnorr.go b/ecc/bw6-633/signature/schnorr/schnorr.go new file mode 100644 index 000000000..3ca930229 --- /dev/null +++ b/ecc/bw6-633/signature/schnorr/schnorr.go @@ -0,0 +1,278 @@ +// 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 schnorr + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/sha512" + "crypto/subtle" + "errors" + "hash" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bw6-633" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fp" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" + "github.com/consensys/gnark-crypto/signature" +) + +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes + sizePublicKey = sizeFp + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + +// PublicKey represents an Schnorr public key +type PublicKey struct { + A bw6633.G1Affine +} + +// PrivateKey represents an Schnorr private key +type PrivateKey struct { + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian +} + +// Signature represents an Schnorr signature +type Signature struct { + R, S [sizeFr]byte +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func randFieldElement(rand io.Reader) (k *big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(order, one) + k.Mod(k, n) + k.Add(k, one) + return +} + +// GenerateKey generates a public and private key pair. +func GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := randFieldElement(rand) + if err != nil { + return nil, err + + } + _, _, g, _ := bw6633.Generators() + + privateKey := new(PrivateKey) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) + return privateKey, nil +} + +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func HashToInt(hash []byte) *big.Int { + if len(hash) > sizeFr { + hash = hash[:sizeFr] + } + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - sizeFr + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand.Reader, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + +// Sign performs the Schnorr signature +// +// k ← 𝔽r (random) +// P = k ⋅ g1Gen +// r = H ( P || m ) +// s = k - x ⋅ r +// signature = {r, s} +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) + csprng, err := nonce(privKey, message) + if err != nil { + return nil, err + } + k, err := randFieldElement(csprng) + if err != nil { + return nil, err + } + + var P bw6633.G1Affine + P.ScalarMultiplicationBase(k) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + + s.Mul(scalar, r) + s.Sub(k, s). + Mod(s, order) + + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) + + return sig.Bytes(), nil +} + +// Verify validates the Schnorr signature +// +// R = s ⋅ Base + r ⋅ publiKey +// H ( R || m ) ?= r +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err + } + + r, s, e := new(big.Int), new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + var P bw6633.G1Jac + P.JointScalarMultiplicationBase(&publicKey.A, s, r) + var _P bw6633.G1Affine + _P.FromJacobian(&P) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + + return e.Cmp(r) == 0, nil + +} diff --git a/ecc/bw6-633/signature/schnorr/schnorr_test.go b/ecc/bw6-633/signature/schnorr/schnorr_test.go new file mode 100644 index 000000000..ae4fd01ee --- /dev/null +++ b/ecc/bw6-633/signature/schnorr/schnorr_test.go @@ -0,0 +1,78 @@ +// 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 schnorr + +import ( + "crypto/rand" + "crypto/sha256" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestSchnorr(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[BW6-633] test the signing and verification", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + flag, _ := publicKey.Verify(sig, msg, hFunc) + + return flag + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignSchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.Sign(msg, hFunc) + } +} + +func BenchmarkVerifySchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.PublicKey.Verify(sig, msg, hFunc) + } +} diff --git a/ecc/bw6-756/signature/schnorr/doc.go b/ecc/bw6-756/signature/schnorr/doc.go new file mode 100644 index 000000000..ef808bee8 --- /dev/null +++ b/ecc/bw6-756/signature/schnorr/doc.go @@ -0,0 +1,23 @@ +// 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 schnorr provides Schnorr signature scheme on the bw6-756 curve. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Schnorr_signature +// - RFC8235: https://www.rfc-editor.org/rfc/rfc8235 +// - BIP-340: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki +package schnorr diff --git a/ecc/bw6-756/signature/schnorr/marshal.go b/ecc/bw6-756/signature/schnorr/marshal.go new file mode 100644 index 000000000..2b92ad686 --- /dev/null +++ b/ecc/bw6-756/signature/schnorr/marshal.go @@ -0,0 +1,108 @@ +// 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 schnorr + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/ecc/bw6-756/signature/schnorr/marshal_test.go b/ecc/bw6-756/signature/schnorr/marshal_test.go new file mode 100644 index 000000000..8b65b5c99 --- /dev/null +++ b/ecc/bw6-756/signature/schnorr/marshal_test.go @@ -0,0 +1,64 @@ +// 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 schnorr + +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[BW6-756] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bw6-756/signature/schnorr/schnorr.go b/ecc/bw6-756/signature/schnorr/schnorr.go new file mode 100644 index 000000000..de465a5f6 --- /dev/null +++ b/ecc/bw6-756/signature/schnorr/schnorr.go @@ -0,0 +1,278 @@ +// 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 schnorr + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/sha512" + "crypto/subtle" + "errors" + "hash" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bw6-756" + "github.com/consensys/gnark-crypto/ecc/bw6-756/fp" + "github.com/consensys/gnark-crypto/ecc/bw6-756/fr" + "github.com/consensys/gnark-crypto/signature" +) + +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes + sizePublicKey = sizeFp + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + +// PublicKey represents an Schnorr public key +type PublicKey struct { + A bw6756.G1Affine +} + +// PrivateKey represents an Schnorr private key +type PrivateKey struct { + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian +} + +// Signature represents an Schnorr signature +type Signature struct { + R, S [sizeFr]byte +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func randFieldElement(rand io.Reader) (k *big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(order, one) + k.Mod(k, n) + k.Add(k, one) + return +} + +// GenerateKey generates a public and private key pair. +func GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := randFieldElement(rand) + if err != nil { + return nil, err + + } + _, _, g, _ := bw6756.Generators() + + privateKey := new(PrivateKey) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) + return privateKey, nil +} + +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func HashToInt(hash []byte) *big.Int { + if len(hash) > sizeFr { + hash = hash[:sizeFr] + } + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - sizeFr + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand.Reader, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + +// Sign performs the Schnorr signature +// +// k ← 𝔽r (random) +// P = k ⋅ g1Gen +// r = H ( P || m ) +// s = k - x ⋅ r +// signature = {r, s} +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) + csprng, err := nonce(privKey, message) + if err != nil { + return nil, err + } + k, err := randFieldElement(csprng) + if err != nil { + return nil, err + } + + var P bw6756.G1Affine + P.ScalarMultiplicationBase(k) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + + s.Mul(scalar, r) + s.Sub(k, s). + Mod(s, order) + + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) + + return sig.Bytes(), nil +} + +// Verify validates the Schnorr signature +// +// R = s ⋅ Base + r ⋅ publiKey +// H ( R || m ) ?= r +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err + } + + r, s, e := new(big.Int), new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + var P bw6756.G1Jac + P.JointScalarMultiplicationBase(&publicKey.A, s, r) + var _P bw6756.G1Affine + _P.FromJacobian(&P) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + + return e.Cmp(r) == 0, nil + +} diff --git a/ecc/bw6-756/signature/schnorr/schnorr_test.go b/ecc/bw6-756/signature/schnorr/schnorr_test.go new file mode 100644 index 000000000..becbf1070 --- /dev/null +++ b/ecc/bw6-756/signature/schnorr/schnorr_test.go @@ -0,0 +1,78 @@ +// 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 schnorr + +import ( + "crypto/rand" + "crypto/sha256" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestSchnorr(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[BW6-756] test the signing and verification", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + flag, _ := publicKey.Verify(sig, msg, hFunc) + + return flag + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignSchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.Sign(msg, hFunc) + } +} + +func BenchmarkVerifySchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.PublicKey.Verify(sig, msg, hFunc) + } +} diff --git a/ecc/bw6-761/signature/schnorr/doc.go b/ecc/bw6-761/signature/schnorr/doc.go new file mode 100644 index 000000000..205afb4a8 --- /dev/null +++ b/ecc/bw6-761/signature/schnorr/doc.go @@ -0,0 +1,23 @@ +// 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 schnorr provides Schnorr signature scheme on the bw6-761 curve. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Schnorr_signature +// - RFC8235: https://www.rfc-editor.org/rfc/rfc8235 +// - BIP-340: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki +package schnorr diff --git a/ecc/bw6-761/signature/schnorr/marshal.go b/ecc/bw6-761/signature/schnorr/marshal.go new file mode 100644 index 000000000..2b92ad686 --- /dev/null +++ b/ecc/bw6-761/signature/schnorr/marshal.go @@ -0,0 +1,108 @@ +// 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 schnorr + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/ecc/bw6-761/signature/schnorr/marshal_test.go b/ecc/bw6-761/signature/schnorr/marshal_test.go new file mode 100644 index 000000000..d53171fce --- /dev/null +++ b/ecc/bw6-761/signature/schnorr/marshal_test.go @@ -0,0 +1,64 @@ +// 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 schnorr + +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[BW6-761] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/bw6-761/signature/schnorr/schnorr.go b/ecc/bw6-761/signature/schnorr/schnorr.go new file mode 100644 index 000000000..13ded779e --- /dev/null +++ b/ecc/bw6-761/signature/schnorr/schnorr.go @@ -0,0 +1,278 @@ +// 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 schnorr + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/sha512" + "crypto/subtle" + "errors" + "hash" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bw6-761" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fp" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + "github.com/consensys/gnark-crypto/signature" +) + +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes + sizePublicKey = sizeFp + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + +// PublicKey represents an Schnorr public key +type PublicKey struct { + A bw6761.G1Affine +} + +// PrivateKey represents an Schnorr private key +type PrivateKey struct { + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian +} + +// Signature represents an Schnorr signature +type Signature struct { + R, S [sizeFr]byte +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func randFieldElement(rand io.Reader) (k *big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(order, one) + k.Mod(k, n) + k.Add(k, one) + return +} + +// GenerateKey generates a public and private key pair. +func GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := randFieldElement(rand) + if err != nil { + return nil, err + + } + _, _, g, _ := bw6761.Generators() + + privateKey := new(PrivateKey) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) + return privateKey, nil +} + +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func HashToInt(hash []byte) *big.Int { + if len(hash) > sizeFr { + hash = hash[:sizeFr] + } + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - sizeFr + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand.Reader, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + +// Sign performs the Schnorr signature +// +// k ← 𝔽r (random) +// P = k ⋅ g1Gen +// r = H ( P || m ) +// s = k - x ⋅ r +// signature = {r, s} +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) + csprng, err := nonce(privKey, message) + if err != nil { + return nil, err + } + k, err := randFieldElement(csprng) + if err != nil { + return nil, err + } + + var P bw6761.G1Affine + P.ScalarMultiplicationBase(k) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + + s.Mul(scalar, r) + s.Sub(k, s). + Mod(s, order) + + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) + + return sig.Bytes(), nil +} + +// Verify validates the Schnorr signature +// +// R = s ⋅ Base + r ⋅ publiKey +// H ( R || m ) ?= r +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err + } + + r, s, e := new(big.Int), new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + var P bw6761.G1Jac + P.JointScalarMultiplicationBase(&publicKey.A, s, r) + var _P bw6761.G1Affine + _P.FromJacobian(&P) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + + return e.Cmp(r) == 0, nil + +} diff --git a/ecc/bw6-761/signature/schnorr/schnorr_test.go b/ecc/bw6-761/signature/schnorr/schnorr_test.go new file mode 100644 index 000000000..f4ab6ce56 --- /dev/null +++ b/ecc/bw6-761/signature/schnorr/schnorr_test.go @@ -0,0 +1,78 @@ +// 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 schnorr + +import ( + "crypto/rand" + "crypto/sha256" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestSchnorr(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[BW6-761] test the signing and verification", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + flag, _ := publicKey.Verify(sig, msg, hFunc) + + return flag + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignSchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.Sign(msg, hFunc) + } +} + +func BenchmarkVerifySchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.PublicKey.Verify(sig, msg, hFunc) + } +} diff --git a/ecc/secp256k1/signature/schnorr/doc.go b/ecc/secp256k1/signature/schnorr/doc.go new file mode 100644 index 000000000..dde769425 --- /dev/null +++ b/ecc/secp256k1/signature/schnorr/doc.go @@ -0,0 +1,23 @@ +// 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 schnorr provides Schnorr signature scheme on the secp256k1 curve. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Schnorr_signature +// - RFC8235: https://www.rfc-editor.org/rfc/rfc8235 +// - BIP-340: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki +package schnorr diff --git a/ecc/secp256k1/signature/schnorr/marshal.go b/ecc/secp256k1/signature/schnorr/marshal.go new file mode 100644 index 000000000..a010a563b --- /dev/null +++ b/ecc/secp256k1/signature/schnorr/marshal.go @@ -0,0 +1,108 @@ +// 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 schnorr + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.RawBytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.RawBytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/ecc/secp256k1/signature/schnorr/marshal_test.go b/ecc/secp256k1/signature/schnorr/marshal_test.go new file mode 100644 index 000000000..c06385c57 --- /dev/null +++ b/ecc/secp256k1/signature/schnorr/marshal_test.go @@ -0,0 +1,64 @@ +// 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 schnorr + +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[SECP256K1] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/secp256k1/signature/schnorr/schnorr.go b/ecc/secp256k1/signature/schnorr/schnorr.go new file mode 100644 index 000000000..c0372a5c7 --- /dev/null +++ b/ecc/secp256k1/signature/schnorr/schnorr.go @@ -0,0 +1,278 @@ +// 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 schnorr + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/sha512" + "crypto/subtle" + "errors" + "hash" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/secp256k1" + "github.com/consensys/gnark-crypto/ecc/secp256k1/fp" + "github.com/consensys/gnark-crypto/ecc/secp256k1/fr" + "github.com/consensys/gnark-crypto/signature" +) + +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes + sizePublicKey = 2 * sizeFp + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + +// PublicKey represents an Schnorr public key +type PublicKey struct { + A secp256k1.G1Affine +} + +// PrivateKey represents an Schnorr private key +type PrivateKey struct { + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian +} + +// Signature represents an Schnorr signature +type Signature struct { + R, S [sizeFr]byte +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func randFieldElement(rand io.Reader) (k *big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(order, one) + k.Mod(k, n) + k.Add(k, one) + return +} + +// GenerateKey generates a public and private key pair. +func GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := randFieldElement(rand) + if err != nil { + return nil, err + + } + _, g := secp256k1.Generators() + + privateKey := new(PrivateKey) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) + return privateKey, nil +} + +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func HashToInt(hash []byte) *big.Int { + if len(hash) > sizeFr { + hash = hash[:sizeFr] + } + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - sizeFr + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand.Reader, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + +// Sign performs the Schnorr signature +// +// k ← 𝔽r (random) +// P = k ⋅ g1Gen +// r = H ( P || m ) +// s = k - x ⋅ r +// signature = {r, s} +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) + csprng, err := nonce(privKey, message) + if err != nil { + return nil, err + } + k, err := randFieldElement(csprng) + if err != nil { + return nil, err + } + + var P secp256k1.G1Affine + P.ScalarMultiplicationBase(k) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + + s.Mul(scalar, r) + s.Sub(k, s). + Mod(s, order) + + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) + + return sig.Bytes(), nil +} + +// Verify validates the Schnorr signature +// +// R = s ⋅ Base + r ⋅ publiKey +// H ( R || m ) ?= r +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err + } + + r, s, e := new(big.Int), new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + var P secp256k1.G1Jac + P.JointScalarMultiplicationBase(&publicKey.A, s, r) + var _P secp256k1.G1Affine + _P.FromJacobian(&P) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + + return e.Cmp(r) == 0, nil + +} diff --git a/ecc/secp256k1/signature/schnorr/schnorr_test.go b/ecc/secp256k1/signature/schnorr/schnorr_test.go new file mode 100644 index 000000000..8af13bee5 --- /dev/null +++ b/ecc/secp256k1/signature/schnorr/schnorr_test.go @@ -0,0 +1,78 @@ +// 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 schnorr + +import ( + "crypto/rand" + "crypto/sha256" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestSchnorr(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[SECP256K1] test the signing and verification", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + flag, _ := publicKey.Verify(sig, msg, hFunc) + + return flag + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignSchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.Sign(msg, hFunc) + } +} + +func BenchmarkVerifySchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.PublicKey.Verify(sig, msg, hFunc) + } +} diff --git a/ecc/stark-curve/signature/schnorr/doc.go b/ecc/stark-curve/signature/schnorr/doc.go new file mode 100644 index 000000000..a815596e4 --- /dev/null +++ b/ecc/stark-curve/signature/schnorr/doc.go @@ -0,0 +1,23 @@ +// 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 schnorr provides Schnorr signature scheme on the stark-curve curve. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Schnorr_signature +// - RFC8235: https://www.rfc-editor.org/rfc/rfc8235 +// - BIP-340: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki +package schnorr diff --git a/ecc/stark-curve/signature/schnorr/marshal.go b/ecc/stark-curve/signature/schnorr/marshal.go new file mode 100644 index 000000000..2b92ad686 --- /dev/null +++ b/ecc/stark-curve/signature/schnorr/marshal.go @@ -0,0 +1,108 @@ +// 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 schnorr + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/ecc/stark-curve/signature/schnorr/marshal_test.go b/ecc/stark-curve/signature/schnorr/marshal_test.go new file mode 100644 index 000000000..10e961c05 --- /dev/null +++ b/ecc/stark-curve/signature/schnorr/marshal_test.go @@ -0,0 +1,64 @@ +// 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 schnorr + +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[STARK-CURVE] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/ecc/stark-curve/signature/schnorr/schnorr.go b/ecc/stark-curve/signature/schnorr/schnorr.go new file mode 100644 index 000000000..55e4f6141 --- /dev/null +++ b/ecc/stark-curve/signature/schnorr/schnorr.go @@ -0,0 +1,278 @@ +// 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 schnorr + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/sha512" + "crypto/subtle" + "errors" + "hash" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/stark-curve" + "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" + "github.com/consensys/gnark-crypto/ecc/stark-curve/fr" + "github.com/consensys/gnark-crypto/signature" +) + +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes + sizePublicKey = sizeFp + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + +// PublicKey represents an Schnorr public key +type PublicKey struct { + A starkcurve.G1Affine +} + +// PrivateKey represents an Schnorr private key +type PrivateKey struct { + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian +} + +// Signature represents an Schnorr signature +type Signature struct { + R, S [sizeFr]byte +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func randFieldElement(rand io.Reader) (k *big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(order, one) + k.Mod(k, n) + k.Add(k, one) + return +} + +// GenerateKey generates a public and private key pair. +func GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := randFieldElement(rand) + if err != nil { + return nil, err + + } + _, g := starkcurve.Generators() + + privateKey := new(PrivateKey) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) + return privateKey, nil +} + +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func HashToInt(hash []byte) *big.Int { + if len(hash) > sizeFr { + hash = hash[:sizeFr] + } + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - sizeFr + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand.Reader, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + +// Sign performs the Schnorr signature +// +// k ← 𝔽r (random) +// P = k ⋅ g1Gen +// r = H ( P || m ) +// s = k - x ⋅ r +// signature = {r, s} +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) + csprng, err := nonce(privKey, message) + if err != nil { + return nil, err + } + k, err := randFieldElement(csprng) + if err != nil { + return nil, err + } + + var P starkcurve.G1Affine + P.ScalarMultiplicationBase(k) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + + s.Mul(scalar, r) + s.Sub(k, s). + Mod(s, order) + + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) + + return sig.Bytes(), nil +} + +// Verify validates the Schnorr signature +// +// R = s ⋅ Base + r ⋅ publiKey +// H ( R || m ) ?= r +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err + } + + r, s, e := new(big.Int), new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + var P starkcurve.G1Jac + P.JointScalarMultiplicationBase(&publicKey.A, s, r) + var _P starkcurve.G1Affine + _P.FromJacobian(&P) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + + return e.Cmp(r) == 0, nil + +} diff --git a/ecc/stark-curve/signature/schnorr/schnorr_test.go b/ecc/stark-curve/signature/schnorr/schnorr_test.go new file mode 100644 index 000000000..2b8ccdb3a --- /dev/null +++ b/ecc/stark-curve/signature/schnorr/schnorr_test.go @@ -0,0 +1,78 @@ +// 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 schnorr + +import ( + "crypto/rand" + "crypto/sha256" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestSchnorr(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[STARK-CURVE] test the signing and verification", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + flag, _ := publicKey.Verify(sig, msg, hFunc) + + return flag + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignSchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.Sign(msg, hFunc) + } +} + +func BenchmarkVerifySchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.PublicKey.Verify(sig, msg, hFunc) + } +} diff --git a/internal/generator/main.go b/internal/generator/main.go index ba2dd97c1..c45fd536b 100644 --- a/internal/generator/main.go +++ b/internal/generator/main.go @@ -25,6 +25,7 @@ import ( "github.com/consensys/gnark-crypto/internal/generator/plookup" "github.com/consensys/gnark-crypto/internal/generator/polynomial" "github.com/consensys/gnark-crypto/internal/generator/signature/ecdsa" + "github.com/consensys/gnark-crypto/internal/generator/signature/schnorr" "github.com/consensys/gnark-crypto/internal/generator/sumcheck" "github.com/consensys/gnark-crypto/internal/generator/test_vector_utils" "github.com/consensys/gnark-crypto/internal/generator/tower" @@ -68,9 +69,12 @@ func main() { ElementType: "fr.Element", } - // generate ecdsa + // generate ecdsa signature assertNoError(ecdsa.Generate(conf, filepath.Join(curveDir, "signature"), bgen)) + // generate schnorr signature + assertNoError(schnorr.Generate(conf, filepath.Join(curveDir, "signature"), bgen)) + if conf.Equal(config.STARK_CURVE) { return // TODO @yelhousni } diff --git a/internal/generator/signature/schnorr/generate.go b/internal/generator/signature/schnorr/generate.go new file mode 100644 index 000000000..918b379eb --- /dev/null +++ b/internal/generator/signature/schnorr/generate.go @@ -0,0 +1,24 @@ +package schnorr + +import ( + "path/filepath" + + "github.com/consensys/bavard" + "github.com/consensys/gnark-crypto/internal/generator/config" +) + +func Generate(conf config.Curve, baseDir string, bgen *bavard.BatchGenerator) error { + // schnorr + conf.Package = "schnorr" + baseDir = filepath.Join(baseDir, conf.Package) + + entries := []bavard.Entry{ + {File: filepath.Join(baseDir, "doc.go"), Templates: []string{"doc.go.tmpl"}}, + {File: filepath.Join(baseDir, "schnorr.go"), Templates: []string{"schnorr.go.tmpl"}}, + {File: filepath.Join(baseDir, "schnorr_test.go"), Templates: []string{"schnorr.test.go.tmpl"}}, + {File: filepath.Join(baseDir, "marshal.go"), Templates: []string{"marshal.go.tmpl"}}, + {File: filepath.Join(baseDir, "marshal_test.go"), Templates: []string{"marshal.test.go.tmpl"}}, + } + return bgen.Generate(conf, conf.Package, "./signature/schnorr/template", entries...) + +} diff --git a/internal/generator/signature/schnorr/template/doc.go.tmpl b/internal/generator/signature/schnorr/template/doc.go.tmpl new file mode 100644 index 000000000..536926c48 --- /dev/null +++ b/internal/generator/signature/schnorr/template/doc.go.tmpl @@ -0,0 +1,8 @@ +// Package {{.Package}} provides Schnorr signature scheme on the {{.Name}} curve. +// +// Documentation: +// - Wikipedia: https://en.wikipedia.org/wiki/Schnorr_signature +// - RFC8235: https://www.rfc-editor.org/rfc/rfc8235 +// - BIP-340: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki +// +package {{.Package}} diff --git a/internal/generator/signature/schnorr/template/marshal.go.tmpl b/internal/generator/signature/schnorr/template/marshal.go.tmpl new file mode 100644 index 000000000..2e76fe21e --- /dev/null +++ b/internal/generator/signature/schnorr/template/marshal.go.tmpl @@ -0,0 +1,98 @@ +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of the public key +// follows https://tools.ietf.org/html/rfc8032#section-3.1 +// and returns a compressed representation of the point (x,y) +// +// x, y are the coordinates of the point +// on the curve as big endian integers. +// compressed representation store x with a parity bit to recompute y +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte +{{- if eq .Name "secp256k1"}} + pkBin := pk.A.RawBytes() +{{- else}} + pkBin := pk.A.Bytes() +{{- end}} + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the curve. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizeFp + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte +{{- if eq .Name "secp256k1"}} + pubkBin := privKey.PublicKey.A.RawBytes() +{{- else}} + pubkBin := privKey.PublicKey.A.Bytes() +{{- end}} + subtle.ConstantTimeCopy(1, res[:sizePublicKey], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizePublicKey:sizePrivateKey], privKey.scalar[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizePublicKey]); err != nil { + return 0, err + } + n += sizePublicKey + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizePublicKey:sizePrivateKey]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 2*sizeFr r||s +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + subtle.ConstantTimeCopy(1, res[:sizeFr], sig.R[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as r||s +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + subtle.ConstantTimeCopy(1, sig.R[:], buf[:sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/internal/generator/signature/schnorr/template/marshal.test.go.tmpl b/internal/generator/signature/schnorr/template/marshal.test.go.tmpl new file mode 100644 index 000000000..5fc66a474 --- /dev/null +++ b/internal/generator/signature/schnorr/template/marshal.test.go.tmpl @@ -0,0 +1,46 @@ +import ( + "crypto/rand" + "crypto/subtle" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +const ( + nbFuzzShort = 10 + nbFuzz = 100 +) + +func TestSerialization(t *testing.T) { + t.Parallel() + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + properties.Property("[{{ toUpper .Name }}] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + func() bool { + privKey, _ := GenerateKey(rand.Reader) + + var end PrivateKey + buf := privKey.Bytes() + n, err := end.SetBytes(buf[:]) + if err != nil { + return false + } + if n != sizePrivateKey { + return false + } + + return end.PublicKey.Equal(&privKey.PublicKey) && subtle.ConstantTimeCompare(end.scalar[:], privKey.scalar[:]) == 1 + + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} diff --git a/internal/generator/signature/schnorr/template/schnorr.go.tmpl b/internal/generator/signature/schnorr/template/schnorr.go.tmpl new file mode 100644 index 000000000..7f1056da6 --- /dev/null +++ b/internal/generator/signature/schnorr/template/schnorr.go.tmpl @@ -0,0 +1,269 @@ +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/sha512" + "crypto/subtle" + "errors" + "hash" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/{{ .Name }}" + "github.com/consensys/gnark-crypto/ecc/{{ .Name }}/fr" + "github.com/consensys/gnark-crypto/ecc/{{ .Name }}/fp" + "github.com/consensys/gnark-crypto/signature" +) + +var errInvalidSig = errors.New("invalid signature") + +const ( + sizeFr = fr.Bytes + sizeFp = fp.Bytes +{{- if eq .Name "secp256k1"}} + sizePublicKey = 2 * sizeFp +{{- else}} + sizePublicKey = sizeFp +{{- end}} + sizePrivateKey = sizeFr + sizePublicKey + sizeSignature = 2 * sizeFr +) + +var order = fr.Modulus() + +// PublicKey represents an Schnorr public key +type PublicKey struct { + A {{ .CurvePackage }}.G1Affine +} + +// PrivateKey represents an Schnorr private key +type PrivateKey struct { + PublicKey PublicKey + scalar [sizeFr]byte // secret scalar, in big Endian +} + +// Signature represents an Schnorr signature +type Signature struct { + R, S [sizeFr]byte +} + +var one = new(big.Int).SetInt64(1) + +// randFieldElement returns a random element of the order of the given +// curve using the procedure given in FIPS 186-4, Appendix B.5.1. +func randFieldElement(rand io.Reader) (k *big.Int, err error) { + b := make([]byte, fr.Bits/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(order, one) + k.Mod(k, n) + k.Add(k, one) + return +} + +// GenerateKey generates a public and private key pair. +func GenerateKey(rand io.Reader) (*PrivateKey, error) { + + k, err := randFieldElement(rand) + if err != nil { + return nil, err + + } + + {{- if or (eq .Name "secp256k1") (eq .Name "stark-curve")}} + _, g := {{ .CurvePackage }}.Generators() + {{- else}} + _, _, g, _ := {{ .CurvePackage }}.Generators() + {{- end}} + + privateKey := new(PrivateKey) + k.FillBytes(privateKey.scalar[:sizeFr]) + privateKey.PublicKey.A.ScalarMultiplication(&g, k) + return privateKey, nil +} + +// HashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4, +// we use the left-most bits of the hash to match the bit-length of the order of +// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3. +func HashToInt(hash []byte) *big.Int { + if len(hash) > sizeFr { + hash = hash[:sizeFr] + } + ret := new(big.Int).SetBytes(hash) + excess := len(hash)*8 - sizeFr + if excess > 0 { + ret.Rsh(ret, uint(excess)) + } + return ret +} + +type zr struct{} + +// Read replaces the contents of dst with zeros. It is safe for concurrent use. +func (zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = zr{} + +const ( + aesIV = "gnark-crypto IV." // must be 16 chars (equal block size) +) + +func nonce(privateKey *PrivateKey, hash []byte) (csprng *cipher.StreamReader, err error) { + // This implementation derives the nonce from an AES-CTR CSPRNG keyed by: + // + // SHA2-512(privateKey.scalar ∥ entropy ∥ hash)[:32] + // + // The CSPRNG key is indifferentiable from a random oracle as shown in + // [Coron], the AES-CTR stream is indifferentiable from a random oracle + // under standard cryptographic assumptions (see [Larsson] for examples). + // + // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf + // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf + + // Get 256 bits of entropy from rand. + entropy := make([]byte, 32) + _, err = io.ReadFull(rand.Reader, entropy) + if err != nil { + return + + } + + // Initialize an SHA-512 hash context; digest... + md := sha512.New() + md.Write(privateKey.scalar[:sizeFr]) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, _ := aes.NewCipher(key) + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng = &cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + + return csprng, err +} + +// Equal compares 2 public keys +func (pub *PublicKey) Equal(x signature.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + bpk := pub.Bytes() + bxx := xx.Bytes() + return subtle.ConstantTimeCompare(bpk, bxx) == 1 +} + +// Public returns the public key associated to the private key. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + +// Sign performs the Schnorr signature +// +// k ← 𝔽r (random) +// P = k ⋅ g1Gen +// r = H ( P || m ) +// s = k - x ⋅ r +// signature = {r, s} +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) + scalar.SetBytes(privKey.scalar[:sizeFr]) + csprng, err := nonce(privKey, message) + if err != nil { + return nil, err + } + k, err := randFieldElement(csprng) + if err != nil { + return nil, err + } + + var P {{ .CurvePackage }}.G1Affine + P.ScalarMultiplicationBase(k) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + + s.Mul(scalar, r) + s.Sub(k, s). + Mod(s, order) + + var sig Signature + r.FillBytes(sig.R[:sizeFr]) + s.FillBytes(sig.S[:sizeFr]) + + return sig.Bytes(), nil +} + +// Verify validates the Schnorr signature +// +// R = s ⋅ Base + r ⋅ publiKey +// H ( R || m ) ?= r +func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err + } + + r, s, e := new(big.Int), new(big.Int), new(big.Int) + r.SetBytes(sig.R[:sizeFr]) + s.SetBytes(sig.S[:sizeFr]) + + var P {{ .CurvePackage }}.G1Jac + P.JointScalarMultiplicationBase(&publicKey.A, s, r) + var _P {{ .CurvePackage }}.G1Affine + _P.FromJacobian(&P) + + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + + return e.Cmp(r) == 0, nil + +} diff --git a/internal/generator/signature/schnorr/template/schnorr.test.go.tmpl b/internal/generator/signature/schnorr/template/schnorr.test.go.tmpl new file mode 100644 index 000000000..de6ac9a4a --- /dev/null +++ b/internal/generator/signature/schnorr/template/schnorr.test.go.tmpl @@ -0,0 +1,60 @@ +import ( + "crypto/rand" + "crypto/sha256" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + +func TestSchnorr(t *testing.T) { + + t.Parallel() + parameters := gopter.DefaultTestParameters() + properties := gopter.NewProperties(parameters) + + properties.Property("[{{ toUpper .Name }}] test the signing and verification", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + flag, _ := publicKey.Verify(sig, msg, hFunc) + + return flag + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} + +// ------------------------------------------------------------ +// benches + +func BenchmarkSignSchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.Sign(msg, hFunc) + } +} + +func BenchmarkVerifySchnorr(b *testing.B) { + + privKey, _ := GenerateKey(rand.Reader) + msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + privKey.PublicKey.Verify(sig, msg, hFunc) + } +} diff --git a/signature/ecdsa/ecdsa.go b/signature/ecdsa/ecdsa.go index 68daac09d..ffe16b590 100644 --- a/signature/ecdsa/ecdsa.go +++ b/signature/ecdsa/ecdsa.go @@ -20,17 +20,17 @@ import ( "io" "github.com/consensys/gnark-crypto/ecc" - ecdsa_bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377/ecdsa" - ecdsa_bls12378 "github.com/consensys/gnark-crypto/ecc/bls12-378/ecdsa" - ecdsa_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/ecdsa" - ecdsa_bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315/ecdsa" - ecdsa_bls24317 "github.com/consensys/gnark-crypto/ecc/bls24-317/ecdsa" - ecdsa_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/ecdsa" - ecdsa_bw6633 "github.com/consensys/gnark-crypto/ecc/bw6-633/ecdsa" - ecdsa_bw6756 "github.com/consensys/gnark-crypto/ecc/bw6-756/ecdsa" - ecdsa_bw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761/ecdsa" - ecdsa_secp256k1 "github.com/consensys/gnark-crypto/ecc/secp256k1/ecdsa" - ecdsa_starkcurve "github.com/consensys/gnark-crypto/ecc/stark-curve/ecdsa" + ecdsa_bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377/signature/ecdsa" + ecdsa_bls12378 "github.com/consensys/gnark-crypto/ecc/bls12-378/signature/ecdsa" + ecdsa_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/signature/ecdsa" + ecdsa_bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315/signature/ecdsa" + ecdsa_bls24317 "github.com/consensys/gnark-crypto/ecc/bls24-317/signature/ecdsa" + ecdsa_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/signature/ecdsa" + ecdsa_bw6633 "github.com/consensys/gnark-crypto/ecc/bw6-633/signature/ecdsa" + ecdsa_bw6756 "github.com/consensys/gnark-crypto/ecc/bw6-756/signature/ecdsa" + ecdsa_bw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761/signature/ecdsa" + ecdsa_secp256k1 "github.com/consensys/gnark-crypto/ecc/secp256k1/signature/ecdsa" + ecdsa_starkcurve "github.com/consensys/gnark-crypto/ecc/stark-curve/signature/ecdsa" "github.com/consensys/gnark-crypto/signature" ) diff --git a/signature/schnorr/schnorr.go b/signature/schnorr/schnorr.go new file mode 100644 index 000000000..9c432cd4b --- /dev/null +++ b/signature/schnorr/schnorr.go @@ -0,0 +1,65 @@ +/* +Copyright © 2020 ConsenSys + +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. +*/ + +package schnorr + +import ( + "io" + + "github.com/consensys/gnark-crypto/ecc" + schnorr_bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377/signature/schnorr" + schnorr_bls12378 "github.com/consensys/gnark-crypto/ecc/bls12-378/signature/schnorr" + schnorr_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/signature/schnorr" + schnorr_bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315/signature/schnorr" + schnorr_bls24317 "github.com/consensys/gnark-crypto/ecc/bls24-317/signature/schnorr" + schnorr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/signature/schnorr" + schnorr_bw6633 "github.com/consensys/gnark-crypto/ecc/bw6-633/signature/schnorr" + schnorr_bw6756 "github.com/consensys/gnark-crypto/ecc/bw6-756/signature/schnorr" + schnorr_bw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761/signature/schnorr" + schnorr_secp256k1 "github.com/consensys/gnark-crypto/ecc/secp256k1/signature/schnorr" + schnorr_starkcurve "github.com/consensys/gnark-crypto/ecc/stark-curve/signature/schnorr" + "github.com/consensys/gnark-crypto/signature" +) + +// New takes a source of randomness and returns a new key pair +func New(ss ecc.ID, r io.Reader) (signature.Signer, error) { + switch ss { + case ecc.BN254: + return schnorr_bn254.GenerateKey(r) + case ecc.BLS12_381: + return schnorr_bls12381.GenerateKey(r) + case ecc.BLS12_377: + return schnorr_bls12377.GenerateKey(r) + case ecc.BLS12_378: + return schnorr_bls12378.GenerateKey(r) + case ecc.BW6_761: + return schnorr_bw6761.GenerateKey(r) + case ecc.BW6_756: + return schnorr_bw6756.GenerateKey(r) + case ecc.BLS24_315: + return schnorr_bls24315.GenerateKey(r) + case ecc.BLS24_317: + return schnorr_bls24317.GenerateKey(r) + case ecc.BW6_633: + return schnorr_bw6633.GenerateKey(r) + case ecc.SECP256K1: + return schnorr_secp256k1.GenerateKey(r) + case ecc.STARK_CURVE: + return schnorr_starkcurve.GenerateKey(r) + default: + panic("not implemented") + } +} From 5bd17bce2b841717d2a31bc45e322c157074501e Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Wed, 25 Jan 2023 17:20:39 +0100 Subject: [PATCH 3/7] test: schnorr with pre-hashed message --- ecc/bls12-377/signature/schnorr/schnorr.go | 68 ++++++++++-------- ecc/bls12-378/signature/schnorr/schnorr.go | 68 ++++++++++-------- ecc/bls12-381/signature/schnorr/schnorr.go | 68 ++++++++++-------- ecc/bls24-315/signature/schnorr/schnorr.go | 68 ++++++++++-------- ecc/bls24-317/signature/schnorr/schnorr.go | 68 ++++++++++-------- ecc/bn254/signature/schnorr/schnorr.go | 68 ++++++++++-------- ecc/bw6-633/signature/schnorr/schnorr.go | 68 ++++++++++-------- ecc/bw6-756/signature/schnorr/schnorr.go | 68 ++++++++++-------- ecc/bw6-761/signature/schnorr/schnorr.go | 68 ++++++++++-------- ecc/secp256k1/signature/schnorr/schnorr.go | 68 ++++++++++-------- ecc/stark-curve/signature/schnorr/schnorr.go | 68 ++++++++++-------- .../schnorr/template/schnorr.go.tmpl | 72 ++++++++++--------- 12 files changed, 458 insertions(+), 362 deletions(-) diff --git a/ecc/bls12-377/signature/schnorr/schnorr.go b/ecc/bls12-377/signature/schnorr/schnorr.go index 70a485c22..328b33516 100644 --- a/ecc/bls12-377/signature/schnorr/schnorr.go +++ b/ecc/bls12-377/signature/schnorr/schnorr.go @@ -207,23 +207,27 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P bls12377.G1Affine P.ScalarMultiplicationBase(k) - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + } else { + r = HashToInt(message) } - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -256,23 +260,27 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P bls12377.G1Affine _P.FromJacobian(&P) - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + } else { + e = HashToInt(message) } - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - return e.Cmp(r) == 0, nil } diff --git a/ecc/bls12-378/signature/schnorr/schnorr.go b/ecc/bls12-378/signature/schnorr/schnorr.go index e7277a5ef..344c3f6f3 100644 --- a/ecc/bls12-378/signature/schnorr/schnorr.go +++ b/ecc/bls12-378/signature/schnorr/schnorr.go @@ -207,23 +207,27 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P bls12378.G1Affine P.ScalarMultiplicationBase(k) - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + } else { + r = HashToInt(message) } - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -256,23 +260,27 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P bls12378.G1Affine _P.FromJacobian(&P) - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + } else { + e = HashToInt(message) } - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - return e.Cmp(r) == 0, nil } diff --git a/ecc/bls12-381/signature/schnorr/schnorr.go b/ecc/bls12-381/signature/schnorr/schnorr.go index 60ebbdfd1..f1d16026f 100644 --- a/ecc/bls12-381/signature/schnorr/schnorr.go +++ b/ecc/bls12-381/signature/schnorr/schnorr.go @@ -207,23 +207,27 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P bls12381.G1Affine P.ScalarMultiplicationBase(k) - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + } else { + r = HashToInt(message) } - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -256,23 +260,27 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P bls12381.G1Affine _P.FromJacobian(&P) - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + } else { + e = HashToInt(message) } - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - return e.Cmp(r) == 0, nil } diff --git a/ecc/bls24-315/signature/schnorr/schnorr.go b/ecc/bls24-315/signature/schnorr/schnorr.go index 7ebbc88e4..83cb61540 100644 --- a/ecc/bls24-315/signature/schnorr/schnorr.go +++ b/ecc/bls24-315/signature/schnorr/schnorr.go @@ -207,23 +207,27 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P bls24315.G1Affine P.ScalarMultiplicationBase(k) - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + } else { + r = HashToInt(message) } - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -256,23 +260,27 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P bls24315.G1Affine _P.FromJacobian(&P) - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + } else { + e = HashToInt(message) } - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - return e.Cmp(r) == 0, nil } diff --git a/ecc/bls24-317/signature/schnorr/schnorr.go b/ecc/bls24-317/signature/schnorr/schnorr.go index 76f5bd465..b45b7d147 100644 --- a/ecc/bls24-317/signature/schnorr/schnorr.go +++ b/ecc/bls24-317/signature/schnorr/schnorr.go @@ -207,23 +207,27 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P bls24317.G1Affine P.ScalarMultiplicationBase(k) - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + } else { + r = HashToInt(message) } - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -256,23 +260,27 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P bls24317.G1Affine _P.FromJacobian(&P) - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + } else { + e = HashToInt(message) } - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - return e.Cmp(r) == 0, nil } diff --git a/ecc/bn254/signature/schnorr/schnorr.go b/ecc/bn254/signature/schnorr/schnorr.go index e16e62e7e..d28e3d63f 100644 --- a/ecc/bn254/signature/schnorr/schnorr.go +++ b/ecc/bn254/signature/schnorr/schnorr.go @@ -207,23 +207,27 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P bn254.G1Affine P.ScalarMultiplicationBase(k) - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + } else { + r = HashToInt(message) } - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -256,23 +260,27 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P bn254.G1Affine _P.FromJacobian(&P) - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + } else { + e = HashToInt(message) } - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - return e.Cmp(r) == 0, nil } diff --git a/ecc/bw6-633/signature/schnorr/schnorr.go b/ecc/bw6-633/signature/schnorr/schnorr.go index 3ca930229..9e8631b49 100644 --- a/ecc/bw6-633/signature/schnorr/schnorr.go +++ b/ecc/bw6-633/signature/schnorr/schnorr.go @@ -207,23 +207,27 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P bw6633.G1Affine P.ScalarMultiplicationBase(k) - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + } else { + r = HashToInt(message) } - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -256,23 +260,27 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P bw6633.G1Affine _P.FromJacobian(&P) - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + } else { + e = HashToInt(message) } - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - return e.Cmp(r) == 0, nil } diff --git a/ecc/bw6-756/signature/schnorr/schnorr.go b/ecc/bw6-756/signature/schnorr/schnorr.go index de465a5f6..f44046979 100644 --- a/ecc/bw6-756/signature/schnorr/schnorr.go +++ b/ecc/bw6-756/signature/schnorr/schnorr.go @@ -207,23 +207,27 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P bw6756.G1Affine P.ScalarMultiplicationBase(k) - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + } else { + r = HashToInt(message) } - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -256,23 +260,27 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P bw6756.G1Affine _P.FromJacobian(&P) - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + } else { + e = HashToInt(message) } - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - return e.Cmp(r) == 0, nil } diff --git a/ecc/bw6-761/signature/schnorr/schnorr.go b/ecc/bw6-761/signature/schnorr/schnorr.go index 13ded779e..90e97627b 100644 --- a/ecc/bw6-761/signature/schnorr/schnorr.go +++ b/ecc/bw6-761/signature/schnorr/schnorr.go @@ -207,23 +207,27 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P bw6761.G1Affine P.ScalarMultiplicationBase(k) - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + } else { + r = HashToInt(message) } - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -256,23 +260,27 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P bw6761.G1Affine _P.FromJacobian(&P) - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + } else { + e = HashToInt(message) } - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - return e.Cmp(r) == 0, nil } diff --git a/ecc/secp256k1/signature/schnorr/schnorr.go b/ecc/secp256k1/signature/schnorr/schnorr.go index c0372a5c7..b168333d9 100644 --- a/ecc/secp256k1/signature/schnorr/schnorr.go +++ b/ecc/secp256k1/signature/schnorr/schnorr.go @@ -207,23 +207,27 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P secp256k1.G1Affine P.ScalarMultiplicationBase(k) - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + } else { + r = HashToInt(message) } - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -256,23 +260,27 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P secp256k1.G1Affine _P.FromJacobian(&P) - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + } else { + e = HashToInt(message) } - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - return e.Cmp(r) == 0, nil } diff --git a/ecc/stark-curve/signature/schnorr/schnorr.go b/ecc/stark-curve/signature/schnorr/schnorr.go index 55e4f6141..852b48ac9 100644 --- a/ecc/stark-curve/signature/schnorr/schnorr.go +++ b/ecc/stark-curve/signature/schnorr/schnorr.go @@ -207,23 +207,27 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P starkcurve.G1Affine P.ScalarMultiplicationBase(k) - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + } else { + r = HashToInt(message) } - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -256,23 +260,27 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P starkcurve.G1Affine _P.FromJacobian(&P) - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + } else { + e = HashToInt(message) } - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - return e.Cmp(r) == 0, nil } diff --git a/internal/generator/signature/schnorr/template/schnorr.go.tmpl b/internal/generator/signature/schnorr/template/schnorr.go.tmpl index 7f1056da6..99b0846c3 100644 --- a/internal/generator/signature/schnorr/template/schnorr.go.tmpl +++ b/internal/generator/signature/schnorr/template/schnorr.go.tmpl @@ -198,22 +198,26 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P {{ .CurvePackage }}.G1Affine P.ScalarMultiplicationBase(k) - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err - } - - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + } else { + r = HashToInt(message) + } s.Mul(scalar, r) s.Sub(k, s). @@ -247,22 +251,26 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P {{ .CurvePackage }}.G1Affine _P.FromJacobian(&P) - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err - } - - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) + if hFunc != nil { + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err + } + + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + } else { + e = HashToInt(message) + } return e.Cmp(r) == 0, nil From 0b42484364b68a708fdf06cd33487c369e76c26f Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 26 Jan 2023 10:54:51 +0100 Subject: [PATCH 4/7] style(schnorr): rename ECDSA to Schnorr in test --- .../generator/signature/schnorr/template/marshal.test.go.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/generator/signature/schnorr/template/marshal.test.go.tmpl b/internal/generator/signature/schnorr/template/marshal.test.go.tmpl index 5fc66a474..2e75d159b 100644 --- a/internal/generator/signature/schnorr/template/marshal.test.go.tmpl +++ b/internal/generator/signature/schnorr/template/marshal.test.go.tmpl @@ -23,7 +23,7 @@ func TestSerialization(t *testing.T) { properties := gopter.NewProperties(parameters) - properties.Property("[{{ toUpper .Name }}] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + properties.Property("[{{ toUpper .Name }}] Schnorr serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( func() bool { privKey, _ := GenerateKey(rand.Reader) From 6ecef50b55ddc1e919e2f0b4b29466fa7c1fcadc Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 26 Jan 2023 11:16:56 +0100 Subject: [PATCH 5/7] test: schnorr with pre-hashed message --- .../signature/schnorr/marshal_test.go | 2 +- .../signature/schnorr/schnorr_test.go | 22 ++++++++++++++----- .../signature/schnorr/marshal_test.go | 2 +- .../signature/schnorr/schnorr_test.go | 22 ++++++++++++++----- .../signature/schnorr/marshal_test.go | 2 +- .../signature/schnorr/schnorr_test.go | 22 ++++++++++++++----- .../signature/schnorr/marshal_test.go | 2 +- .../signature/schnorr/schnorr_test.go | 22 ++++++++++++++----- .../signature/schnorr/marshal_test.go | 2 +- .../signature/schnorr/schnorr_test.go | 22 ++++++++++++++----- ecc/bn254/signature/schnorr/marshal_test.go | 2 +- ecc/bn254/signature/schnorr/schnorr_test.go | 22 ++++++++++++++----- ecc/bw6-633/signature/schnorr/marshal_test.go | 2 +- ecc/bw6-633/signature/schnorr/schnorr_test.go | 22 ++++++++++++++----- ecc/bw6-756/signature/schnorr/marshal_test.go | 2 +- ecc/bw6-756/signature/schnorr/schnorr_test.go | 22 ++++++++++++++----- ecc/bw6-761/signature/schnorr/marshal_test.go | 2 +- ecc/bw6-761/signature/schnorr/schnorr_test.go | 22 ++++++++++++++----- .../signature/schnorr/marshal_test.go | 2 +- .../signature/schnorr/schnorr_test.go | 22 ++++++++++++++----- .../signature/schnorr/marshal_test.go | 2 +- .../signature/schnorr/schnorr_test.go | 22 ++++++++++++++----- .../schnorr/template/schnorr.test.go.tmpl | 22 ++++++++++++++----- 23 files changed, 215 insertions(+), 71 deletions(-) diff --git a/ecc/bls12-377/signature/schnorr/marshal_test.go b/ecc/bls12-377/signature/schnorr/marshal_test.go index 5bd24a7e5..fedca5a07 100644 --- a/ecc/bls12-377/signature/schnorr/marshal_test.go +++ b/ecc/bls12-377/signature/schnorr/marshal_test.go @@ -41,7 +41,7 @@ func TestSerialization(t *testing.T) { properties := gopter.NewProperties(parameters) - properties.Property("[BLS12-377] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + properties.Property("[BLS12-377] Schnorr serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( func() bool { privKey, _ := GenerateKey(rand.Reader) diff --git a/ecc/bls12-377/signature/schnorr/schnorr_test.go b/ecc/bls12-377/signature/schnorr/schnorr_test.go index 68b7c8c57..157c71856 100644 --- a/ecc/bls12-377/signature/schnorr/schnorr_test.go +++ b/ecc/bls12-377/signature/schnorr/schnorr_test.go @@ -46,6 +46,20 @@ func TestSchnorr(t *testing.T) { }, )) + properties.Property("[BLS12-377] test the signing and verification (pre-hashed)", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + sig, _ := privKey.Sign(msg, nil) + flag, _ := publicKey.Verify(sig, msg, nil) + + return flag + }, + )) + properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -57,10 +71,9 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, hFunc) + privKey.Sign(msg, nil) } } @@ -68,11 +81,10 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() - sig, _ := privKey.Sign(msg, hFunc) + sig, _ := privKey.Sign(msg, nil) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, hFunc) + privKey.PublicKey.Verify(sig, msg, nil) } } diff --git a/ecc/bls12-378/signature/schnorr/marshal_test.go b/ecc/bls12-378/signature/schnorr/marshal_test.go index 3c81b214c..a5bed6622 100644 --- a/ecc/bls12-378/signature/schnorr/marshal_test.go +++ b/ecc/bls12-378/signature/schnorr/marshal_test.go @@ -41,7 +41,7 @@ func TestSerialization(t *testing.T) { properties := gopter.NewProperties(parameters) - properties.Property("[BLS12-378] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + properties.Property("[BLS12-378] Schnorr serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( func() bool { privKey, _ := GenerateKey(rand.Reader) diff --git a/ecc/bls12-378/signature/schnorr/schnorr_test.go b/ecc/bls12-378/signature/schnorr/schnorr_test.go index 69d54ce8f..12e42d9ca 100644 --- a/ecc/bls12-378/signature/schnorr/schnorr_test.go +++ b/ecc/bls12-378/signature/schnorr/schnorr_test.go @@ -46,6 +46,20 @@ func TestSchnorr(t *testing.T) { }, )) + properties.Property("[BLS12-378] test the signing and verification (pre-hashed)", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + sig, _ := privKey.Sign(msg, nil) + flag, _ := publicKey.Verify(sig, msg, nil) + + return flag + }, + )) + properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -57,10 +71,9 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, hFunc) + privKey.Sign(msg, nil) } } @@ -68,11 +81,10 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() - sig, _ := privKey.Sign(msg, hFunc) + sig, _ := privKey.Sign(msg, nil) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, hFunc) + privKey.PublicKey.Verify(sig, msg, nil) } } diff --git a/ecc/bls12-381/signature/schnorr/marshal_test.go b/ecc/bls12-381/signature/schnorr/marshal_test.go index df30517a8..254233609 100644 --- a/ecc/bls12-381/signature/schnorr/marshal_test.go +++ b/ecc/bls12-381/signature/schnorr/marshal_test.go @@ -41,7 +41,7 @@ func TestSerialization(t *testing.T) { properties := gopter.NewProperties(parameters) - properties.Property("[BLS12-381] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + properties.Property("[BLS12-381] Schnorr serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( func() bool { privKey, _ := GenerateKey(rand.Reader) diff --git a/ecc/bls12-381/signature/schnorr/schnorr_test.go b/ecc/bls12-381/signature/schnorr/schnorr_test.go index ca692100c..50d39e61b 100644 --- a/ecc/bls12-381/signature/schnorr/schnorr_test.go +++ b/ecc/bls12-381/signature/schnorr/schnorr_test.go @@ -46,6 +46,20 @@ func TestSchnorr(t *testing.T) { }, )) + properties.Property("[BLS12-381] test the signing and verification (pre-hashed)", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + sig, _ := privKey.Sign(msg, nil) + flag, _ := publicKey.Verify(sig, msg, nil) + + return flag + }, + )) + properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -57,10 +71,9 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, hFunc) + privKey.Sign(msg, nil) } } @@ -68,11 +81,10 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() - sig, _ := privKey.Sign(msg, hFunc) + sig, _ := privKey.Sign(msg, nil) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, hFunc) + privKey.PublicKey.Verify(sig, msg, nil) } } diff --git a/ecc/bls24-315/signature/schnorr/marshal_test.go b/ecc/bls24-315/signature/schnorr/marshal_test.go index 43bcbeb6b..f75a8bccf 100644 --- a/ecc/bls24-315/signature/schnorr/marshal_test.go +++ b/ecc/bls24-315/signature/schnorr/marshal_test.go @@ -41,7 +41,7 @@ func TestSerialization(t *testing.T) { properties := gopter.NewProperties(parameters) - properties.Property("[BLS24-315] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + properties.Property("[BLS24-315] Schnorr serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( func() bool { privKey, _ := GenerateKey(rand.Reader) diff --git a/ecc/bls24-315/signature/schnorr/schnorr_test.go b/ecc/bls24-315/signature/schnorr/schnorr_test.go index a36590b40..aee5be60f 100644 --- a/ecc/bls24-315/signature/schnorr/schnorr_test.go +++ b/ecc/bls24-315/signature/schnorr/schnorr_test.go @@ -46,6 +46,20 @@ func TestSchnorr(t *testing.T) { }, )) + properties.Property("[BLS24-315] test the signing and verification (pre-hashed)", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + sig, _ := privKey.Sign(msg, nil) + flag, _ := publicKey.Verify(sig, msg, nil) + + return flag + }, + )) + properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -57,10 +71,9 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, hFunc) + privKey.Sign(msg, nil) } } @@ -68,11 +81,10 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() - sig, _ := privKey.Sign(msg, hFunc) + sig, _ := privKey.Sign(msg, nil) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, hFunc) + privKey.PublicKey.Verify(sig, msg, nil) } } diff --git a/ecc/bls24-317/signature/schnorr/marshal_test.go b/ecc/bls24-317/signature/schnorr/marshal_test.go index cf16dbb36..cc55bde47 100644 --- a/ecc/bls24-317/signature/schnorr/marshal_test.go +++ b/ecc/bls24-317/signature/schnorr/marshal_test.go @@ -41,7 +41,7 @@ func TestSerialization(t *testing.T) { properties := gopter.NewProperties(parameters) - properties.Property("[BLS24-317] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + properties.Property("[BLS24-317] Schnorr serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( func() bool { privKey, _ := GenerateKey(rand.Reader) diff --git a/ecc/bls24-317/signature/schnorr/schnorr_test.go b/ecc/bls24-317/signature/schnorr/schnorr_test.go index 49ec67942..fdadf0eca 100644 --- a/ecc/bls24-317/signature/schnorr/schnorr_test.go +++ b/ecc/bls24-317/signature/schnorr/schnorr_test.go @@ -46,6 +46,20 @@ func TestSchnorr(t *testing.T) { }, )) + properties.Property("[BLS24-317] test the signing and verification (pre-hashed)", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + sig, _ := privKey.Sign(msg, nil) + flag, _ := publicKey.Verify(sig, msg, nil) + + return flag + }, + )) + properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -57,10 +71,9 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, hFunc) + privKey.Sign(msg, nil) } } @@ -68,11 +81,10 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() - sig, _ := privKey.Sign(msg, hFunc) + sig, _ := privKey.Sign(msg, nil) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, hFunc) + privKey.PublicKey.Verify(sig, msg, nil) } } diff --git a/ecc/bn254/signature/schnorr/marshal_test.go b/ecc/bn254/signature/schnorr/marshal_test.go index 169c1697c..f0bdd21eb 100644 --- a/ecc/bn254/signature/schnorr/marshal_test.go +++ b/ecc/bn254/signature/schnorr/marshal_test.go @@ -41,7 +41,7 @@ func TestSerialization(t *testing.T) { properties := gopter.NewProperties(parameters) - properties.Property("[BN254] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + properties.Property("[BN254] Schnorr serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( func() bool { privKey, _ := GenerateKey(rand.Reader) diff --git a/ecc/bn254/signature/schnorr/schnorr_test.go b/ecc/bn254/signature/schnorr/schnorr_test.go index 9e8496fc0..dcabca4f4 100644 --- a/ecc/bn254/signature/schnorr/schnorr_test.go +++ b/ecc/bn254/signature/schnorr/schnorr_test.go @@ -46,6 +46,20 @@ func TestSchnorr(t *testing.T) { }, )) + properties.Property("[BN254] test the signing and verification (pre-hashed)", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + sig, _ := privKey.Sign(msg, nil) + flag, _ := publicKey.Verify(sig, msg, nil) + + return flag + }, + )) + properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -57,10 +71,9 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, hFunc) + privKey.Sign(msg, nil) } } @@ -68,11 +81,10 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() - sig, _ := privKey.Sign(msg, hFunc) + sig, _ := privKey.Sign(msg, nil) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, hFunc) + privKey.PublicKey.Verify(sig, msg, nil) } } diff --git a/ecc/bw6-633/signature/schnorr/marshal_test.go b/ecc/bw6-633/signature/schnorr/marshal_test.go index 3314c79ec..dae0361ae 100644 --- a/ecc/bw6-633/signature/schnorr/marshal_test.go +++ b/ecc/bw6-633/signature/schnorr/marshal_test.go @@ -41,7 +41,7 @@ func TestSerialization(t *testing.T) { properties := gopter.NewProperties(parameters) - properties.Property("[BW6-633] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + properties.Property("[BW6-633] Schnorr serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( func() bool { privKey, _ := GenerateKey(rand.Reader) diff --git a/ecc/bw6-633/signature/schnorr/schnorr_test.go b/ecc/bw6-633/signature/schnorr/schnorr_test.go index ae4fd01ee..a9bb91e56 100644 --- a/ecc/bw6-633/signature/schnorr/schnorr_test.go +++ b/ecc/bw6-633/signature/schnorr/schnorr_test.go @@ -46,6 +46,20 @@ func TestSchnorr(t *testing.T) { }, )) + properties.Property("[BW6-633] test the signing and verification (pre-hashed)", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + sig, _ := privKey.Sign(msg, nil) + flag, _ := publicKey.Verify(sig, msg, nil) + + return flag + }, + )) + properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -57,10 +71,9 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, hFunc) + privKey.Sign(msg, nil) } } @@ -68,11 +81,10 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() - sig, _ := privKey.Sign(msg, hFunc) + sig, _ := privKey.Sign(msg, nil) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, hFunc) + privKey.PublicKey.Verify(sig, msg, nil) } } diff --git a/ecc/bw6-756/signature/schnorr/marshal_test.go b/ecc/bw6-756/signature/schnorr/marshal_test.go index 8b65b5c99..8d8ba9b2c 100644 --- a/ecc/bw6-756/signature/schnorr/marshal_test.go +++ b/ecc/bw6-756/signature/schnorr/marshal_test.go @@ -41,7 +41,7 @@ func TestSerialization(t *testing.T) { properties := gopter.NewProperties(parameters) - properties.Property("[BW6-756] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + properties.Property("[BW6-756] Schnorr serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( func() bool { privKey, _ := GenerateKey(rand.Reader) diff --git a/ecc/bw6-756/signature/schnorr/schnorr_test.go b/ecc/bw6-756/signature/schnorr/schnorr_test.go index becbf1070..b8f3ff26a 100644 --- a/ecc/bw6-756/signature/schnorr/schnorr_test.go +++ b/ecc/bw6-756/signature/schnorr/schnorr_test.go @@ -46,6 +46,20 @@ func TestSchnorr(t *testing.T) { }, )) + properties.Property("[BW6-756] test the signing and verification (pre-hashed)", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + sig, _ := privKey.Sign(msg, nil) + flag, _ := publicKey.Verify(sig, msg, nil) + + return flag + }, + )) + properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -57,10 +71,9 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, hFunc) + privKey.Sign(msg, nil) } } @@ -68,11 +81,10 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() - sig, _ := privKey.Sign(msg, hFunc) + sig, _ := privKey.Sign(msg, nil) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, hFunc) + privKey.PublicKey.Verify(sig, msg, nil) } } diff --git a/ecc/bw6-761/signature/schnorr/marshal_test.go b/ecc/bw6-761/signature/schnorr/marshal_test.go index d53171fce..cded0c9ad 100644 --- a/ecc/bw6-761/signature/schnorr/marshal_test.go +++ b/ecc/bw6-761/signature/schnorr/marshal_test.go @@ -41,7 +41,7 @@ func TestSerialization(t *testing.T) { properties := gopter.NewProperties(parameters) - properties.Property("[BW6-761] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + properties.Property("[BW6-761] Schnorr serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( func() bool { privKey, _ := GenerateKey(rand.Reader) diff --git a/ecc/bw6-761/signature/schnorr/schnorr_test.go b/ecc/bw6-761/signature/schnorr/schnorr_test.go index f4ab6ce56..ea0054339 100644 --- a/ecc/bw6-761/signature/schnorr/schnorr_test.go +++ b/ecc/bw6-761/signature/schnorr/schnorr_test.go @@ -46,6 +46,20 @@ func TestSchnorr(t *testing.T) { }, )) + properties.Property("[BW6-761] test the signing and verification (pre-hashed)", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + sig, _ := privKey.Sign(msg, nil) + flag, _ := publicKey.Verify(sig, msg, nil) + + return flag + }, + )) + properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -57,10 +71,9 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, hFunc) + privKey.Sign(msg, nil) } } @@ -68,11 +81,10 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() - sig, _ := privKey.Sign(msg, hFunc) + sig, _ := privKey.Sign(msg, nil) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, hFunc) + privKey.PublicKey.Verify(sig, msg, nil) } } diff --git a/ecc/secp256k1/signature/schnorr/marshal_test.go b/ecc/secp256k1/signature/schnorr/marshal_test.go index c06385c57..ee0dd08e5 100644 --- a/ecc/secp256k1/signature/schnorr/marshal_test.go +++ b/ecc/secp256k1/signature/schnorr/marshal_test.go @@ -41,7 +41,7 @@ func TestSerialization(t *testing.T) { properties := gopter.NewProperties(parameters) - properties.Property("[SECP256K1] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + properties.Property("[SECP256K1] Schnorr serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( func() bool { privKey, _ := GenerateKey(rand.Reader) diff --git a/ecc/secp256k1/signature/schnorr/schnorr_test.go b/ecc/secp256k1/signature/schnorr/schnorr_test.go index 8af13bee5..99fa41bec 100644 --- a/ecc/secp256k1/signature/schnorr/schnorr_test.go +++ b/ecc/secp256k1/signature/schnorr/schnorr_test.go @@ -46,6 +46,20 @@ func TestSchnorr(t *testing.T) { }, )) + properties.Property("[SECP256K1] test the signing and verification (pre-hashed)", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + sig, _ := privKey.Sign(msg, nil) + flag, _ := publicKey.Verify(sig, msg, nil) + + return flag + }, + )) + properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -57,10 +71,9 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, hFunc) + privKey.Sign(msg, nil) } } @@ -68,11 +81,10 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() - sig, _ := privKey.Sign(msg, hFunc) + sig, _ := privKey.Sign(msg, nil) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, hFunc) + privKey.PublicKey.Verify(sig, msg, nil) } } diff --git a/ecc/stark-curve/signature/schnorr/marshal_test.go b/ecc/stark-curve/signature/schnorr/marshal_test.go index 10e961c05..64bd65c14 100644 --- a/ecc/stark-curve/signature/schnorr/marshal_test.go +++ b/ecc/stark-curve/signature/schnorr/marshal_test.go @@ -41,7 +41,7 @@ func TestSerialization(t *testing.T) { properties := gopter.NewProperties(parameters) - properties.Property("[STARK-CURVE] ECDSA serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( + properties.Property("[STARK-CURVE] Schnorr serialization: SetBytes(Bytes()) should stay the same", prop.ForAll( func() bool { privKey, _ := GenerateKey(rand.Reader) diff --git a/ecc/stark-curve/signature/schnorr/schnorr_test.go b/ecc/stark-curve/signature/schnorr/schnorr_test.go index 2b8ccdb3a..b9b111eac 100644 --- a/ecc/stark-curve/signature/schnorr/schnorr_test.go +++ b/ecc/stark-curve/signature/schnorr/schnorr_test.go @@ -46,6 +46,20 @@ func TestSchnorr(t *testing.T) { }, )) + properties.Property("[STARK-CURVE] test the signing and verification (pre-hashed)", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + sig, _ := privKey.Sign(msg, nil) + flag, _ := publicKey.Verify(sig, msg, nil) + + return flag + }, + )) + properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -57,10 +71,9 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, hFunc) + privKey.Sign(msg, nil) } } @@ -68,11 +81,10 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() - sig, _ := privKey.Sign(msg, hFunc) + sig, _ := privKey.Sign(msg, nil) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, hFunc) + privKey.PublicKey.Verify(sig, msg, nil) } } diff --git a/internal/generator/signature/schnorr/template/schnorr.test.go.tmpl b/internal/generator/signature/schnorr/template/schnorr.test.go.tmpl index de6ac9a4a..9f7293193 100644 --- a/internal/generator/signature/schnorr/template/schnorr.test.go.tmpl +++ b/internal/generator/signature/schnorr/template/schnorr.test.go.tmpl @@ -28,6 +28,20 @@ func TestSchnorr(t *testing.T) { }, )) + properties.Property("[{{ toUpper .Name }}] test the signing and verification (pre-hashed)", prop.ForAll( + func() bool { + + privKey, _ := GenerateKey(rand.Reader) + publicKey := privKey.PublicKey + + msg := []byte("testing Schnorr") + sig, _ := privKey.Sign(msg, nil) + flag, _ := publicKey.Verify(sig, msg, nil) + + return flag + }, + )) + properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -39,10 +53,9 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, hFunc) + privKey.Sign(msg, nil) } } @@ -50,11 +63,10 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - hFunc := sha256.New() - sig, _ := privKey.Sign(msg, hFunc) + sig, _ := privKey.Sign(msg, nil) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, hFunc) + privKey.PublicKey.Verify(sig, msg, nil) } } From 1ebec7b351c7ca8b4ce786875f6f590e1606486a Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 27 Jan 2023 09:17:50 +0100 Subject: [PATCH 6/7] perf(ecdsa): no bigInt allocation --- ecc/bls12-377/signature/ecdsa/ecdsa.go | 4 ++-- ecc/bls12-378/signature/ecdsa/ecdsa.go | 4 ++-- ecc/bls12-381/signature/ecdsa/ecdsa.go | 4 ++-- ecc/bls24-315/signature/ecdsa/ecdsa.go | 4 ++-- ecc/bls24-317/signature/ecdsa/ecdsa.go | 4 ++-- ecc/bn254/signature/ecdsa/ecdsa.go | 4 ++-- ecc/bw6-633/signature/ecdsa/ecdsa.go | 4 ++-- ecc/bw6-756/signature/ecdsa/ecdsa.go | 4 ++-- ecc/bw6-761/signature/ecdsa/ecdsa.go | 4 ++-- ecc/secp256k1/signature/ecdsa/ecdsa.go | 4 ++-- ecc/stark-curve/signature/ecdsa/ecdsa.go | 4 ++-- internal/generator/signature/ecdsa/template/ecdsa.go.tmpl | 4 ++-- 12 files changed, 24 insertions(+), 24 deletions(-) diff --git a/ecc/bls12-377/signature/ecdsa/ecdsa.go b/ecc/bls12-377/signature/ecdsa/ecdsa.go index 6f27e1535..cc13e8ac6 100644 --- a/ecc/bls12-377/signature/ecdsa/ecdsa.go +++ b/ecc/bls12-377/signature/ecdsa/ecdsa.go @@ -220,7 +220,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) } s.Mul(r, scalar) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) @@ -270,7 +270,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo sInv := new(big.Int).ModInverse(s, order) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) diff --git a/ecc/bls12-378/signature/ecdsa/ecdsa.go b/ecc/bls12-378/signature/ecdsa/ecdsa.go index bfee7fe4e..44c297cc8 100644 --- a/ecc/bls12-378/signature/ecdsa/ecdsa.go +++ b/ecc/bls12-378/signature/ecdsa/ecdsa.go @@ -220,7 +220,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) } s.Mul(r, scalar) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) @@ -270,7 +270,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo sInv := new(big.Int).ModInverse(s, order) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) diff --git a/ecc/bls12-381/signature/ecdsa/ecdsa.go b/ecc/bls12-381/signature/ecdsa/ecdsa.go index 82925c627..9039ee388 100644 --- a/ecc/bls12-381/signature/ecdsa/ecdsa.go +++ b/ecc/bls12-381/signature/ecdsa/ecdsa.go @@ -220,7 +220,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) } s.Mul(r, scalar) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) @@ -270,7 +270,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo sInv := new(big.Int).ModInverse(s, order) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) diff --git a/ecc/bls24-315/signature/ecdsa/ecdsa.go b/ecc/bls24-315/signature/ecdsa/ecdsa.go index c9fe0878f..e1309b2f3 100644 --- a/ecc/bls24-315/signature/ecdsa/ecdsa.go +++ b/ecc/bls24-315/signature/ecdsa/ecdsa.go @@ -220,7 +220,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) } s.Mul(r, scalar) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) @@ -270,7 +270,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo sInv := new(big.Int).ModInverse(s, order) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) diff --git a/ecc/bls24-317/signature/ecdsa/ecdsa.go b/ecc/bls24-317/signature/ecdsa/ecdsa.go index 97c553246..dfcbab66c 100644 --- a/ecc/bls24-317/signature/ecdsa/ecdsa.go +++ b/ecc/bls24-317/signature/ecdsa/ecdsa.go @@ -220,7 +220,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) } s.Mul(r, scalar) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) @@ -270,7 +270,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo sInv := new(big.Int).ModInverse(s, order) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) diff --git a/ecc/bn254/signature/ecdsa/ecdsa.go b/ecc/bn254/signature/ecdsa/ecdsa.go index e55205377..8593d6a72 100644 --- a/ecc/bn254/signature/ecdsa/ecdsa.go +++ b/ecc/bn254/signature/ecdsa/ecdsa.go @@ -220,7 +220,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) } s.Mul(r, scalar) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) @@ -270,7 +270,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo sInv := new(big.Int).ModInverse(s, order) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) diff --git a/ecc/bw6-633/signature/ecdsa/ecdsa.go b/ecc/bw6-633/signature/ecdsa/ecdsa.go index 67efe8ea1..f264a1e47 100644 --- a/ecc/bw6-633/signature/ecdsa/ecdsa.go +++ b/ecc/bw6-633/signature/ecdsa/ecdsa.go @@ -220,7 +220,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) } s.Mul(r, scalar) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) @@ -270,7 +270,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo sInv := new(big.Int).ModInverse(s, order) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) diff --git a/ecc/bw6-756/signature/ecdsa/ecdsa.go b/ecc/bw6-756/signature/ecdsa/ecdsa.go index 1131bb1f7..11c7725b5 100644 --- a/ecc/bw6-756/signature/ecdsa/ecdsa.go +++ b/ecc/bw6-756/signature/ecdsa/ecdsa.go @@ -220,7 +220,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) } s.Mul(r, scalar) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) @@ -270,7 +270,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo sInv := new(big.Int).ModInverse(s, order) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) diff --git a/ecc/bw6-761/signature/ecdsa/ecdsa.go b/ecc/bw6-761/signature/ecdsa/ecdsa.go index 8ad854c43..7a6669fca 100644 --- a/ecc/bw6-761/signature/ecdsa/ecdsa.go +++ b/ecc/bw6-761/signature/ecdsa/ecdsa.go @@ -220,7 +220,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) } s.Mul(r, scalar) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) @@ -270,7 +270,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo sInv := new(big.Int).ModInverse(s, order) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) diff --git a/ecc/secp256k1/signature/ecdsa/ecdsa.go b/ecc/secp256k1/signature/ecdsa/ecdsa.go index a2abdbbab..de7c735da 100644 --- a/ecc/secp256k1/signature/ecdsa/ecdsa.go +++ b/ecc/secp256k1/signature/ecdsa/ecdsa.go @@ -220,7 +220,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) } s.Mul(r, scalar) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) @@ -270,7 +270,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo sInv := new(big.Int).ModInverse(s, order) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) diff --git a/ecc/stark-curve/signature/ecdsa/ecdsa.go b/ecc/stark-curve/signature/ecdsa/ecdsa.go index bd1221196..4707f3219 100644 --- a/ecc/stark-curve/signature/ecdsa/ecdsa.go +++ b/ecc/stark-curve/signature/ecdsa/ecdsa.go @@ -220,7 +220,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) } s.Mul(r, scalar) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) @@ -270,7 +270,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo sInv := new(big.Int).ModInverse(s, order) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) diff --git a/internal/generator/signature/ecdsa/template/ecdsa.go.tmpl b/internal/generator/signature/ecdsa/template/ecdsa.go.tmpl index dd536c0e1..fd953cdf4 100644 --- a/internal/generator/signature/ecdsa/template/ecdsa.go.tmpl +++ b/internal/generator/signature/ecdsa/template/ecdsa.go.tmpl @@ -211,7 +211,7 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) } s.Mul(r, scalar) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) @@ -261,7 +261,7 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo sInv := new(big.Int).ModInverse(s, order) - m := new(big.Int) + var m *big.Int if hFunc != nil { // compute the hash of the message as an integer dataToHash := make([]byte, len(message)) From 0cc03c4860c1ff1284bc8060964b393e51f853ee Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Fri, 27 Jan 2023 13:23:53 +0100 Subject: [PATCH 7/7] fix(schnorr): enforce hash function as FS challenge --- ecc/bls12-377/signature/ecdsa/ecdsa.go | 3 - ecc/bls12-377/signature/schnorr/schnorr.go | 83 ++++++++++--------- .../signature/schnorr/schnorr_test.go | 22 ++--- ecc/bls12-378/signature/ecdsa/ecdsa.go | 3 - ecc/bls12-378/signature/schnorr/schnorr.go | 83 ++++++++++--------- .../signature/schnorr/schnorr_test.go | 22 ++--- ecc/bls12-381/signature/ecdsa/ecdsa.go | 3 - ecc/bls12-381/signature/schnorr/schnorr.go | 83 ++++++++++--------- .../signature/schnorr/schnorr_test.go | 22 ++--- ecc/bls24-315/signature/ecdsa/ecdsa.go | 3 - ecc/bls24-315/signature/schnorr/schnorr.go | 83 ++++++++++--------- .../signature/schnorr/schnorr_test.go | 22 ++--- ecc/bls24-317/signature/ecdsa/ecdsa.go | 3 - ecc/bls24-317/signature/schnorr/schnorr.go | 83 ++++++++++--------- .../signature/schnorr/schnorr_test.go | 22 ++--- ecc/bn254/signature/ecdsa/ecdsa.go | 3 - ecc/bn254/signature/schnorr/schnorr.go | 83 ++++++++++--------- ecc/bn254/signature/schnorr/schnorr_test.go | 22 ++--- ecc/bw6-633/signature/ecdsa/ecdsa.go | 3 - ecc/bw6-633/signature/schnorr/schnorr.go | 83 ++++++++++--------- ecc/bw6-633/signature/schnorr/schnorr_test.go | 22 ++--- ecc/bw6-756/signature/ecdsa/ecdsa.go | 3 - ecc/bw6-756/signature/schnorr/schnorr.go | 83 ++++++++++--------- ecc/bw6-756/signature/schnorr/schnorr_test.go | 22 ++--- ecc/bw6-761/signature/ecdsa/ecdsa.go | 3 - ecc/bw6-761/signature/schnorr/schnorr.go | 83 ++++++++++--------- ecc/bw6-761/signature/schnorr/schnorr_test.go | 22 ++--- ecc/secp256k1/signature/ecdsa/ecdsa.go | 3 - ecc/secp256k1/signature/schnorr/schnorr.go | 83 ++++++++++--------- .../signature/schnorr/schnorr_test.go | 22 ++--- ecc/stark-curve/signature/ecdsa/ecdsa.go | 3 - ecc/stark-curve/signature/schnorr/schnorr.go | 83 ++++++++++--------- .../signature/schnorr/schnorr_test.go | 22 ++--- .../signature/ecdsa/template/ecdsa.go.tmpl | 3 - .../schnorr/template/schnorr.go.tmpl | 83 ++++++++++--------- .../schnorr/template/schnorr.test.go.tmpl | 22 ++--- 36 files changed, 588 insertions(+), 708 deletions(-) diff --git a/ecc/bls12-377/signature/ecdsa/ecdsa.go b/ecc/bls12-377/signature/ecdsa/ecdsa.go index cc13e8ac6..395313d7f 100644 --- a/ecc/bls12-377/signature/ecdsa/ecdsa.go +++ b/ecc/bls12-377/signature/ecdsa/ecdsa.go @@ -22,7 +22,6 @@ import ( "crypto/rand" "crypto/sha512" "crypto/subtle" - "errors" "hash" "io" "math/big" @@ -33,8 +32,6 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") - const ( sizeFr = fr.Bytes sizeFp = fp.Bytes diff --git a/ecc/bls12-377/signature/schnorr/schnorr.go b/ecc/bls12-377/signature/schnorr/schnorr.go index 328b33516..bd0571b1b 100644 --- a/ecc/bls12-377/signature/schnorr/schnorr.go +++ b/ecc/bls12-377/signature/schnorr/schnorr.go @@ -33,7 +33,7 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") +var errHashNeeded = errors.New("hFunc cannot be nil. We need a hash for Fiat-Shamir.") const ( sizeFr = fr.Bytes @@ -193,6 +193,13 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // s = k - x ⋅ r // signature = {r, s} func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return nil, errHashNeeded + } + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) csprng, err := nonce(privKey, message) @@ -207,27 +214,23 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P bls12377.G1Affine P.ScalarMultiplicationBase(k) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err - } - - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - } else { - r = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err } + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -245,6 +248,12 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) // H ( R || m ) ?= r func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return false, errHashNeeded + } + // Deserialize the signature var sig Signature if _, err := sig.SetBytes(sigBin); err != nil { @@ -260,27 +269,23 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P bls12377.G1Affine _P.FromJacobian(&P) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err - } - - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - } else { - e = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err } + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + return e.Cmp(r) == 0, nil } diff --git a/ecc/bls12-377/signature/schnorr/schnorr_test.go b/ecc/bls12-377/signature/schnorr/schnorr_test.go index 157c71856..68b7c8c57 100644 --- a/ecc/bls12-377/signature/schnorr/schnorr_test.go +++ b/ecc/bls12-377/signature/schnorr/schnorr_test.go @@ -46,20 +46,6 @@ func TestSchnorr(t *testing.T) { }, )) - properties.Property("[BLS12-377] test the signing and verification (pre-hashed)", prop.ForAll( - func() bool { - - privKey, _ := GenerateKey(rand.Reader) - publicKey := privKey.PublicKey - - msg := []byte("testing Schnorr") - sig, _ := privKey.Sign(msg, nil) - flag, _ := publicKey.Verify(sig, msg, nil) - - return flag - }, - )) - properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -71,9 +57,10 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, nil) + privKey.Sign(msg, hFunc) } } @@ -81,10 +68,11 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - sig, _ := privKey.Sign(msg, nil) + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, nil) + privKey.PublicKey.Verify(sig, msg, hFunc) } } diff --git a/ecc/bls12-378/signature/ecdsa/ecdsa.go b/ecc/bls12-378/signature/ecdsa/ecdsa.go index 44c297cc8..57d13d572 100644 --- a/ecc/bls12-378/signature/ecdsa/ecdsa.go +++ b/ecc/bls12-378/signature/ecdsa/ecdsa.go @@ -22,7 +22,6 @@ import ( "crypto/rand" "crypto/sha512" "crypto/subtle" - "errors" "hash" "io" "math/big" @@ -33,8 +32,6 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") - const ( sizeFr = fr.Bytes sizeFp = fp.Bytes diff --git a/ecc/bls12-378/signature/schnorr/schnorr.go b/ecc/bls12-378/signature/schnorr/schnorr.go index 344c3f6f3..17ca91369 100644 --- a/ecc/bls12-378/signature/schnorr/schnorr.go +++ b/ecc/bls12-378/signature/schnorr/schnorr.go @@ -33,7 +33,7 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") +var errHashNeeded = errors.New("hFunc cannot be nil. We need a hash for Fiat-Shamir.") const ( sizeFr = fr.Bytes @@ -193,6 +193,13 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // s = k - x ⋅ r // signature = {r, s} func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return nil, errHashNeeded + } + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) csprng, err := nonce(privKey, message) @@ -207,27 +214,23 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P bls12378.G1Affine P.ScalarMultiplicationBase(k) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err - } - - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - } else { - r = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err } + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -245,6 +248,12 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) // H ( R || m ) ?= r func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return false, errHashNeeded + } + // Deserialize the signature var sig Signature if _, err := sig.SetBytes(sigBin); err != nil { @@ -260,27 +269,23 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P bls12378.G1Affine _P.FromJacobian(&P) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err - } - - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - } else { - e = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err } + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + return e.Cmp(r) == 0, nil } diff --git a/ecc/bls12-378/signature/schnorr/schnorr_test.go b/ecc/bls12-378/signature/schnorr/schnorr_test.go index 12e42d9ca..69d54ce8f 100644 --- a/ecc/bls12-378/signature/schnorr/schnorr_test.go +++ b/ecc/bls12-378/signature/schnorr/schnorr_test.go @@ -46,20 +46,6 @@ func TestSchnorr(t *testing.T) { }, )) - properties.Property("[BLS12-378] test the signing and verification (pre-hashed)", prop.ForAll( - func() bool { - - privKey, _ := GenerateKey(rand.Reader) - publicKey := privKey.PublicKey - - msg := []byte("testing Schnorr") - sig, _ := privKey.Sign(msg, nil) - flag, _ := publicKey.Verify(sig, msg, nil) - - return flag - }, - )) - properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -71,9 +57,10 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, nil) + privKey.Sign(msg, hFunc) } } @@ -81,10 +68,11 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - sig, _ := privKey.Sign(msg, nil) + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, nil) + privKey.PublicKey.Verify(sig, msg, hFunc) } } diff --git a/ecc/bls12-381/signature/ecdsa/ecdsa.go b/ecc/bls12-381/signature/ecdsa/ecdsa.go index 9039ee388..f110a9483 100644 --- a/ecc/bls12-381/signature/ecdsa/ecdsa.go +++ b/ecc/bls12-381/signature/ecdsa/ecdsa.go @@ -22,7 +22,6 @@ import ( "crypto/rand" "crypto/sha512" "crypto/subtle" - "errors" "hash" "io" "math/big" @@ -33,8 +32,6 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") - const ( sizeFr = fr.Bytes sizeFp = fp.Bytes diff --git a/ecc/bls12-381/signature/schnorr/schnorr.go b/ecc/bls12-381/signature/schnorr/schnorr.go index f1d16026f..a23d4cf37 100644 --- a/ecc/bls12-381/signature/schnorr/schnorr.go +++ b/ecc/bls12-381/signature/schnorr/schnorr.go @@ -33,7 +33,7 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") +var errHashNeeded = errors.New("hFunc cannot be nil. We need a hash for Fiat-Shamir.") const ( sizeFr = fr.Bytes @@ -193,6 +193,13 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // s = k - x ⋅ r // signature = {r, s} func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return nil, errHashNeeded + } + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) csprng, err := nonce(privKey, message) @@ -207,27 +214,23 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P bls12381.G1Affine P.ScalarMultiplicationBase(k) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err - } - - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - } else { - r = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err } + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -245,6 +248,12 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) // H ( R || m ) ?= r func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return false, errHashNeeded + } + // Deserialize the signature var sig Signature if _, err := sig.SetBytes(sigBin); err != nil { @@ -260,27 +269,23 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P bls12381.G1Affine _P.FromJacobian(&P) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err - } - - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - } else { - e = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err } + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + return e.Cmp(r) == 0, nil } diff --git a/ecc/bls12-381/signature/schnorr/schnorr_test.go b/ecc/bls12-381/signature/schnorr/schnorr_test.go index 50d39e61b..ca692100c 100644 --- a/ecc/bls12-381/signature/schnorr/schnorr_test.go +++ b/ecc/bls12-381/signature/schnorr/schnorr_test.go @@ -46,20 +46,6 @@ func TestSchnorr(t *testing.T) { }, )) - properties.Property("[BLS12-381] test the signing and verification (pre-hashed)", prop.ForAll( - func() bool { - - privKey, _ := GenerateKey(rand.Reader) - publicKey := privKey.PublicKey - - msg := []byte("testing Schnorr") - sig, _ := privKey.Sign(msg, nil) - flag, _ := publicKey.Verify(sig, msg, nil) - - return flag - }, - )) - properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -71,9 +57,10 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, nil) + privKey.Sign(msg, hFunc) } } @@ -81,10 +68,11 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - sig, _ := privKey.Sign(msg, nil) + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, nil) + privKey.PublicKey.Verify(sig, msg, hFunc) } } diff --git a/ecc/bls24-315/signature/ecdsa/ecdsa.go b/ecc/bls24-315/signature/ecdsa/ecdsa.go index e1309b2f3..1e419e34e 100644 --- a/ecc/bls24-315/signature/ecdsa/ecdsa.go +++ b/ecc/bls24-315/signature/ecdsa/ecdsa.go @@ -22,7 +22,6 @@ import ( "crypto/rand" "crypto/sha512" "crypto/subtle" - "errors" "hash" "io" "math/big" @@ -33,8 +32,6 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") - const ( sizeFr = fr.Bytes sizeFp = fp.Bytes diff --git a/ecc/bls24-315/signature/schnorr/schnorr.go b/ecc/bls24-315/signature/schnorr/schnorr.go index 83cb61540..8743a7dc7 100644 --- a/ecc/bls24-315/signature/schnorr/schnorr.go +++ b/ecc/bls24-315/signature/schnorr/schnorr.go @@ -33,7 +33,7 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") +var errHashNeeded = errors.New("hFunc cannot be nil. We need a hash for Fiat-Shamir.") const ( sizeFr = fr.Bytes @@ -193,6 +193,13 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // s = k - x ⋅ r // signature = {r, s} func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return nil, errHashNeeded + } + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) csprng, err := nonce(privKey, message) @@ -207,27 +214,23 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P bls24315.G1Affine P.ScalarMultiplicationBase(k) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err - } - - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - } else { - r = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err } + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -245,6 +248,12 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) // H ( R || m ) ?= r func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return false, errHashNeeded + } + // Deserialize the signature var sig Signature if _, err := sig.SetBytes(sigBin); err != nil { @@ -260,27 +269,23 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P bls24315.G1Affine _P.FromJacobian(&P) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err - } - - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - } else { - e = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err } + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + return e.Cmp(r) == 0, nil } diff --git a/ecc/bls24-315/signature/schnorr/schnorr_test.go b/ecc/bls24-315/signature/schnorr/schnorr_test.go index aee5be60f..a36590b40 100644 --- a/ecc/bls24-315/signature/schnorr/schnorr_test.go +++ b/ecc/bls24-315/signature/schnorr/schnorr_test.go @@ -46,20 +46,6 @@ func TestSchnorr(t *testing.T) { }, )) - properties.Property("[BLS24-315] test the signing and verification (pre-hashed)", prop.ForAll( - func() bool { - - privKey, _ := GenerateKey(rand.Reader) - publicKey := privKey.PublicKey - - msg := []byte("testing Schnorr") - sig, _ := privKey.Sign(msg, nil) - flag, _ := publicKey.Verify(sig, msg, nil) - - return flag - }, - )) - properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -71,9 +57,10 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, nil) + privKey.Sign(msg, hFunc) } } @@ -81,10 +68,11 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - sig, _ := privKey.Sign(msg, nil) + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, nil) + privKey.PublicKey.Verify(sig, msg, hFunc) } } diff --git a/ecc/bls24-317/signature/ecdsa/ecdsa.go b/ecc/bls24-317/signature/ecdsa/ecdsa.go index dfcbab66c..ce3ff756d 100644 --- a/ecc/bls24-317/signature/ecdsa/ecdsa.go +++ b/ecc/bls24-317/signature/ecdsa/ecdsa.go @@ -22,7 +22,6 @@ import ( "crypto/rand" "crypto/sha512" "crypto/subtle" - "errors" "hash" "io" "math/big" @@ -33,8 +32,6 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") - const ( sizeFr = fr.Bytes sizeFp = fp.Bytes diff --git a/ecc/bls24-317/signature/schnorr/schnorr.go b/ecc/bls24-317/signature/schnorr/schnorr.go index b45b7d147..9c5fd5a59 100644 --- a/ecc/bls24-317/signature/schnorr/schnorr.go +++ b/ecc/bls24-317/signature/schnorr/schnorr.go @@ -33,7 +33,7 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") +var errHashNeeded = errors.New("hFunc cannot be nil. We need a hash for Fiat-Shamir.") const ( sizeFr = fr.Bytes @@ -193,6 +193,13 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // s = k - x ⋅ r // signature = {r, s} func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return nil, errHashNeeded + } + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) csprng, err := nonce(privKey, message) @@ -207,27 +214,23 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P bls24317.G1Affine P.ScalarMultiplicationBase(k) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err - } - - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - } else { - r = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err } + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -245,6 +248,12 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) // H ( R || m ) ?= r func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return false, errHashNeeded + } + // Deserialize the signature var sig Signature if _, err := sig.SetBytes(sigBin); err != nil { @@ -260,27 +269,23 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P bls24317.G1Affine _P.FromJacobian(&P) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err - } - - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - } else { - e = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err } + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + return e.Cmp(r) == 0, nil } diff --git a/ecc/bls24-317/signature/schnorr/schnorr_test.go b/ecc/bls24-317/signature/schnorr/schnorr_test.go index fdadf0eca..49ec67942 100644 --- a/ecc/bls24-317/signature/schnorr/schnorr_test.go +++ b/ecc/bls24-317/signature/schnorr/schnorr_test.go @@ -46,20 +46,6 @@ func TestSchnorr(t *testing.T) { }, )) - properties.Property("[BLS24-317] test the signing and verification (pre-hashed)", prop.ForAll( - func() bool { - - privKey, _ := GenerateKey(rand.Reader) - publicKey := privKey.PublicKey - - msg := []byte("testing Schnorr") - sig, _ := privKey.Sign(msg, nil) - flag, _ := publicKey.Verify(sig, msg, nil) - - return flag - }, - )) - properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -71,9 +57,10 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, nil) + privKey.Sign(msg, hFunc) } } @@ -81,10 +68,11 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - sig, _ := privKey.Sign(msg, nil) + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, nil) + privKey.PublicKey.Verify(sig, msg, hFunc) } } diff --git a/ecc/bn254/signature/ecdsa/ecdsa.go b/ecc/bn254/signature/ecdsa/ecdsa.go index 8593d6a72..165ff0b75 100644 --- a/ecc/bn254/signature/ecdsa/ecdsa.go +++ b/ecc/bn254/signature/ecdsa/ecdsa.go @@ -22,7 +22,6 @@ import ( "crypto/rand" "crypto/sha512" "crypto/subtle" - "errors" "hash" "io" "math/big" @@ -33,8 +32,6 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") - const ( sizeFr = fr.Bytes sizeFp = fp.Bytes diff --git a/ecc/bn254/signature/schnorr/schnorr.go b/ecc/bn254/signature/schnorr/schnorr.go index d28e3d63f..b62b8668a 100644 --- a/ecc/bn254/signature/schnorr/schnorr.go +++ b/ecc/bn254/signature/schnorr/schnorr.go @@ -33,7 +33,7 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") +var errHashNeeded = errors.New("hFunc cannot be nil. We need a hash for Fiat-Shamir.") const ( sizeFr = fr.Bytes @@ -193,6 +193,13 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // s = k - x ⋅ r // signature = {r, s} func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return nil, errHashNeeded + } + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) csprng, err := nonce(privKey, message) @@ -207,27 +214,23 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P bn254.G1Affine P.ScalarMultiplicationBase(k) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err - } - - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - } else { - r = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err } + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -245,6 +248,12 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) // H ( R || m ) ?= r func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return false, errHashNeeded + } + // Deserialize the signature var sig Signature if _, err := sig.SetBytes(sigBin); err != nil { @@ -260,27 +269,23 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P bn254.G1Affine _P.FromJacobian(&P) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err - } - - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - } else { - e = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err } + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + return e.Cmp(r) == 0, nil } diff --git a/ecc/bn254/signature/schnorr/schnorr_test.go b/ecc/bn254/signature/schnorr/schnorr_test.go index dcabca4f4..9e8496fc0 100644 --- a/ecc/bn254/signature/schnorr/schnorr_test.go +++ b/ecc/bn254/signature/schnorr/schnorr_test.go @@ -46,20 +46,6 @@ func TestSchnorr(t *testing.T) { }, )) - properties.Property("[BN254] test the signing and verification (pre-hashed)", prop.ForAll( - func() bool { - - privKey, _ := GenerateKey(rand.Reader) - publicKey := privKey.PublicKey - - msg := []byte("testing Schnorr") - sig, _ := privKey.Sign(msg, nil) - flag, _ := publicKey.Verify(sig, msg, nil) - - return flag - }, - )) - properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -71,9 +57,10 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, nil) + privKey.Sign(msg, hFunc) } } @@ -81,10 +68,11 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - sig, _ := privKey.Sign(msg, nil) + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, nil) + privKey.PublicKey.Verify(sig, msg, hFunc) } } diff --git a/ecc/bw6-633/signature/ecdsa/ecdsa.go b/ecc/bw6-633/signature/ecdsa/ecdsa.go index f264a1e47..9e7ff866f 100644 --- a/ecc/bw6-633/signature/ecdsa/ecdsa.go +++ b/ecc/bw6-633/signature/ecdsa/ecdsa.go @@ -22,7 +22,6 @@ import ( "crypto/rand" "crypto/sha512" "crypto/subtle" - "errors" "hash" "io" "math/big" @@ -33,8 +32,6 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") - const ( sizeFr = fr.Bytes sizeFp = fp.Bytes diff --git a/ecc/bw6-633/signature/schnorr/schnorr.go b/ecc/bw6-633/signature/schnorr/schnorr.go index 9e8631b49..74abc730f 100644 --- a/ecc/bw6-633/signature/schnorr/schnorr.go +++ b/ecc/bw6-633/signature/schnorr/schnorr.go @@ -33,7 +33,7 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") +var errHashNeeded = errors.New("hFunc cannot be nil. We need a hash for Fiat-Shamir.") const ( sizeFr = fr.Bytes @@ -193,6 +193,13 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // s = k - x ⋅ r // signature = {r, s} func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return nil, errHashNeeded + } + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) csprng, err := nonce(privKey, message) @@ -207,27 +214,23 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P bw6633.G1Affine P.ScalarMultiplicationBase(k) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err - } - - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - } else { - r = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err } + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -245,6 +248,12 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) // H ( R || m ) ?= r func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return false, errHashNeeded + } + // Deserialize the signature var sig Signature if _, err := sig.SetBytes(sigBin); err != nil { @@ -260,27 +269,23 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P bw6633.G1Affine _P.FromJacobian(&P) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err - } - - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - } else { - e = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err } + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + return e.Cmp(r) == 0, nil } diff --git a/ecc/bw6-633/signature/schnorr/schnorr_test.go b/ecc/bw6-633/signature/schnorr/schnorr_test.go index a9bb91e56..ae4fd01ee 100644 --- a/ecc/bw6-633/signature/schnorr/schnorr_test.go +++ b/ecc/bw6-633/signature/schnorr/schnorr_test.go @@ -46,20 +46,6 @@ func TestSchnorr(t *testing.T) { }, )) - properties.Property("[BW6-633] test the signing and verification (pre-hashed)", prop.ForAll( - func() bool { - - privKey, _ := GenerateKey(rand.Reader) - publicKey := privKey.PublicKey - - msg := []byte("testing Schnorr") - sig, _ := privKey.Sign(msg, nil) - flag, _ := publicKey.Verify(sig, msg, nil) - - return flag - }, - )) - properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -71,9 +57,10 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, nil) + privKey.Sign(msg, hFunc) } } @@ -81,10 +68,11 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - sig, _ := privKey.Sign(msg, nil) + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, nil) + privKey.PublicKey.Verify(sig, msg, hFunc) } } diff --git a/ecc/bw6-756/signature/ecdsa/ecdsa.go b/ecc/bw6-756/signature/ecdsa/ecdsa.go index 11c7725b5..ca52448b9 100644 --- a/ecc/bw6-756/signature/ecdsa/ecdsa.go +++ b/ecc/bw6-756/signature/ecdsa/ecdsa.go @@ -22,7 +22,6 @@ import ( "crypto/rand" "crypto/sha512" "crypto/subtle" - "errors" "hash" "io" "math/big" @@ -33,8 +32,6 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") - const ( sizeFr = fr.Bytes sizeFp = fp.Bytes diff --git a/ecc/bw6-756/signature/schnorr/schnorr.go b/ecc/bw6-756/signature/schnorr/schnorr.go index f44046979..035fd172f 100644 --- a/ecc/bw6-756/signature/schnorr/schnorr.go +++ b/ecc/bw6-756/signature/schnorr/schnorr.go @@ -33,7 +33,7 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") +var errHashNeeded = errors.New("hFunc cannot be nil. We need a hash for Fiat-Shamir.") const ( sizeFr = fr.Bytes @@ -193,6 +193,13 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // s = k - x ⋅ r // signature = {r, s} func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return nil, errHashNeeded + } + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) csprng, err := nonce(privKey, message) @@ -207,27 +214,23 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P bw6756.G1Affine P.ScalarMultiplicationBase(k) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err - } - - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - } else { - r = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err } + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -245,6 +248,12 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) // H ( R || m ) ?= r func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return false, errHashNeeded + } + // Deserialize the signature var sig Signature if _, err := sig.SetBytes(sigBin); err != nil { @@ -260,27 +269,23 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P bw6756.G1Affine _P.FromJacobian(&P) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err - } - - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - } else { - e = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err } + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + return e.Cmp(r) == 0, nil } diff --git a/ecc/bw6-756/signature/schnorr/schnorr_test.go b/ecc/bw6-756/signature/schnorr/schnorr_test.go index b8f3ff26a..becbf1070 100644 --- a/ecc/bw6-756/signature/schnorr/schnorr_test.go +++ b/ecc/bw6-756/signature/schnorr/schnorr_test.go @@ -46,20 +46,6 @@ func TestSchnorr(t *testing.T) { }, )) - properties.Property("[BW6-756] test the signing and verification (pre-hashed)", prop.ForAll( - func() bool { - - privKey, _ := GenerateKey(rand.Reader) - publicKey := privKey.PublicKey - - msg := []byte("testing Schnorr") - sig, _ := privKey.Sign(msg, nil) - flag, _ := publicKey.Verify(sig, msg, nil) - - return flag - }, - )) - properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -71,9 +57,10 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, nil) + privKey.Sign(msg, hFunc) } } @@ -81,10 +68,11 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - sig, _ := privKey.Sign(msg, nil) + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, nil) + privKey.PublicKey.Verify(sig, msg, hFunc) } } diff --git a/ecc/bw6-761/signature/ecdsa/ecdsa.go b/ecc/bw6-761/signature/ecdsa/ecdsa.go index 7a6669fca..e996c7672 100644 --- a/ecc/bw6-761/signature/ecdsa/ecdsa.go +++ b/ecc/bw6-761/signature/ecdsa/ecdsa.go @@ -22,7 +22,6 @@ import ( "crypto/rand" "crypto/sha512" "crypto/subtle" - "errors" "hash" "io" "math/big" @@ -33,8 +32,6 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") - const ( sizeFr = fr.Bytes sizeFp = fp.Bytes diff --git a/ecc/bw6-761/signature/schnorr/schnorr.go b/ecc/bw6-761/signature/schnorr/schnorr.go index 90e97627b..697be7d85 100644 --- a/ecc/bw6-761/signature/schnorr/schnorr.go +++ b/ecc/bw6-761/signature/schnorr/schnorr.go @@ -33,7 +33,7 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") +var errHashNeeded = errors.New("hFunc cannot be nil. We need a hash for Fiat-Shamir.") const ( sizeFr = fr.Bytes @@ -193,6 +193,13 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // s = k - x ⋅ r // signature = {r, s} func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return nil, errHashNeeded + } + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) csprng, err := nonce(privKey, message) @@ -207,27 +214,23 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P bw6761.G1Affine P.ScalarMultiplicationBase(k) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err - } - - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - } else { - r = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err } + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -245,6 +248,12 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) // H ( R || m ) ?= r func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return false, errHashNeeded + } + // Deserialize the signature var sig Signature if _, err := sig.SetBytes(sigBin); err != nil { @@ -260,27 +269,23 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P bw6761.G1Affine _P.FromJacobian(&P) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err - } - - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - } else { - e = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err } + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + return e.Cmp(r) == 0, nil } diff --git a/ecc/bw6-761/signature/schnorr/schnorr_test.go b/ecc/bw6-761/signature/schnorr/schnorr_test.go index ea0054339..f4ab6ce56 100644 --- a/ecc/bw6-761/signature/schnorr/schnorr_test.go +++ b/ecc/bw6-761/signature/schnorr/schnorr_test.go @@ -46,20 +46,6 @@ func TestSchnorr(t *testing.T) { }, )) - properties.Property("[BW6-761] test the signing and verification (pre-hashed)", prop.ForAll( - func() bool { - - privKey, _ := GenerateKey(rand.Reader) - publicKey := privKey.PublicKey - - msg := []byte("testing Schnorr") - sig, _ := privKey.Sign(msg, nil) - flag, _ := publicKey.Verify(sig, msg, nil) - - return flag - }, - )) - properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -71,9 +57,10 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, nil) + privKey.Sign(msg, hFunc) } } @@ -81,10 +68,11 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - sig, _ := privKey.Sign(msg, nil) + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, nil) + privKey.PublicKey.Verify(sig, msg, hFunc) } } diff --git a/ecc/secp256k1/signature/ecdsa/ecdsa.go b/ecc/secp256k1/signature/ecdsa/ecdsa.go index de7c735da..f2acadbdc 100644 --- a/ecc/secp256k1/signature/ecdsa/ecdsa.go +++ b/ecc/secp256k1/signature/ecdsa/ecdsa.go @@ -22,7 +22,6 @@ import ( "crypto/rand" "crypto/sha512" "crypto/subtle" - "errors" "hash" "io" "math/big" @@ -33,8 +32,6 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") - const ( sizeFr = fr.Bytes sizeFp = fp.Bytes diff --git a/ecc/secp256k1/signature/schnorr/schnorr.go b/ecc/secp256k1/signature/schnorr/schnorr.go index b168333d9..cf7413347 100644 --- a/ecc/secp256k1/signature/schnorr/schnorr.go +++ b/ecc/secp256k1/signature/schnorr/schnorr.go @@ -33,7 +33,7 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") +var errHashNeeded = errors.New("hFunc cannot be nil. We need a hash for Fiat-Shamir.") const ( sizeFr = fr.Bytes @@ -193,6 +193,13 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // s = k - x ⋅ r // signature = {r, s} func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return nil, errHashNeeded + } + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) csprng, err := nonce(privKey, message) @@ -207,27 +214,23 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P secp256k1.G1Affine P.ScalarMultiplicationBase(k) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err - } - - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - } else { - r = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err } + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -245,6 +248,12 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) // H ( R || m ) ?= r func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return false, errHashNeeded + } + // Deserialize the signature var sig Signature if _, err := sig.SetBytes(sigBin); err != nil { @@ -260,27 +269,23 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P secp256k1.G1Affine _P.FromJacobian(&P) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err - } - - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - } else { - e = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err } + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + return e.Cmp(r) == 0, nil } diff --git a/ecc/secp256k1/signature/schnorr/schnorr_test.go b/ecc/secp256k1/signature/schnorr/schnorr_test.go index 99fa41bec..8af13bee5 100644 --- a/ecc/secp256k1/signature/schnorr/schnorr_test.go +++ b/ecc/secp256k1/signature/schnorr/schnorr_test.go @@ -46,20 +46,6 @@ func TestSchnorr(t *testing.T) { }, )) - properties.Property("[SECP256K1] test the signing and verification (pre-hashed)", prop.ForAll( - func() bool { - - privKey, _ := GenerateKey(rand.Reader) - publicKey := privKey.PublicKey - - msg := []byte("testing Schnorr") - sig, _ := privKey.Sign(msg, nil) - flag, _ := publicKey.Verify(sig, msg, nil) - - return flag - }, - )) - properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -71,9 +57,10 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, nil) + privKey.Sign(msg, hFunc) } } @@ -81,10 +68,11 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - sig, _ := privKey.Sign(msg, nil) + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, nil) + privKey.PublicKey.Verify(sig, msg, hFunc) } } diff --git a/ecc/stark-curve/signature/ecdsa/ecdsa.go b/ecc/stark-curve/signature/ecdsa/ecdsa.go index 4707f3219..9808f0f1e 100644 --- a/ecc/stark-curve/signature/ecdsa/ecdsa.go +++ b/ecc/stark-curve/signature/ecdsa/ecdsa.go @@ -22,7 +22,6 @@ import ( "crypto/rand" "crypto/sha512" "crypto/subtle" - "errors" "hash" "io" "math/big" @@ -33,8 +32,6 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") - const ( sizeFr = fr.Bytes sizeFp = fp.Bytes diff --git a/ecc/stark-curve/signature/schnorr/schnorr.go b/ecc/stark-curve/signature/schnorr/schnorr.go index 852b48ac9..c42bcc188 100644 --- a/ecc/stark-curve/signature/schnorr/schnorr.go +++ b/ecc/stark-curve/signature/schnorr/schnorr.go @@ -33,7 +33,7 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") +var errHashNeeded = errors.New("hFunc cannot be nil. We need a hash for Fiat-Shamir.") const ( sizeFr = fr.Bytes @@ -193,6 +193,13 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // s = k - x ⋅ r // signature = {r, s} func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return nil, errHashNeeded + } + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) csprng, err := nonce(privKey, message) @@ -207,27 +214,23 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P starkcurve.G1Affine P.ScalarMultiplicationBase(k) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err - } - - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - } else { - r = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err } + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -245,6 +248,12 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) // H ( R || m ) ?= r func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return false, errHashNeeded + } + // Deserialize the signature var sig Signature if _, err := sig.SetBytes(sigBin); err != nil { @@ -260,27 +269,23 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P starkcurve.G1Affine _P.FromJacobian(&P) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err - } - - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - } else { - e = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err } + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + return e.Cmp(r) == 0, nil } diff --git a/ecc/stark-curve/signature/schnorr/schnorr_test.go b/ecc/stark-curve/signature/schnorr/schnorr_test.go index b9b111eac..2b8ccdb3a 100644 --- a/ecc/stark-curve/signature/schnorr/schnorr_test.go +++ b/ecc/stark-curve/signature/schnorr/schnorr_test.go @@ -46,20 +46,6 @@ func TestSchnorr(t *testing.T) { }, )) - properties.Property("[STARK-CURVE] test the signing and verification (pre-hashed)", prop.ForAll( - func() bool { - - privKey, _ := GenerateKey(rand.Reader) - publicKey := privKey.PublicKey - - msg := []byte("testing Schnorr") - sig, _ := privKey.Sign(msg, nil) - flag, _ := publicKey.Verify(sig, msg, nil) - - return flag - }, - )) - properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -71,9 +57,10 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, nil) + privKey.Sign(msg, hFunc) } } @@ -81,10 +68,11 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - sig, _ := privKey.Sign(msg, nil) + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, nil) + privKey.PublicKey.Verify(sig, msg, hFunc) } } diff --git a/internal/generator/signature/ecdsa/template/ecdsa.go.tmpl b/internal/generator/signature/ecdsa/template/ecdsa.go.tmpl index fd953cdf4..2dfe2a951 100644 --- a/internal/generator/signature/ecdsa/template/ecdsa.go.tmpl +++ b/internal/generator/signature/ecdsa/template/ecdsa.go.tmpl @@ -4,7 +4,6 @@ import ( "crypto/rand" "crypto/sha512" "crypto/subtle" - "errors" "hash" "io" "math/big" @@ -15,8 +14,6 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") - const ( sizeFr = fr.Bytes sizeFp = fp.Bytes diff --git a/internal/generator/signature/schnorr/template/schnorr.go.tmpl b/internal/generator/signature/schnorr/template/schnorr.go.tmpl index 99b0846c3..01e83b44d 100644 --- a/internal/generator/signature/schnorr/template/schnorr.go.tmpl +++ b/internal/generator/signature/schnorr/template/schnorr.go.tmpl @@ -15,7 +15,7 @@ import ( "github.com/consensys/gnark-crypto/signature" ) -var errInvalidSig = errors.New("invalid signature") +var errHashNeeded = errors.New("hFunc cannot be nil. We need a hash for Fiat-Shamir.") const ( sizeFr = fr.Bytes @@ -184,6 +184,13 @@ func (privKey *PrivateKey) Public() signature.PublicKey { // s = k - x ⋅ r // signature = {r, s} func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return nil, errHashNeeded + } + scalar, r, s := new(big.Int), new(big.Int), new(big.Int) scalar.SetBytes(privKey.scalar[:sizeFr]) csprng, err := nonce(privKey, message) @@ -198,27 +205,23 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) var P {{ .CurvePackage }}.G1Affine P.ScalarMultiplicationBase(k) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := P.X.Bytes() - PY := P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err = hFunc.Write(dataToHash[:]) - if err != nil { - return nil, err - } - - hramBin := hFunc.Sum(nil) - r = HashToInt(hramBin) - } else { - r = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := P.X.Bytes() + PY := P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err = hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err } + hramBin := hFunc.Sum(nil) + r = HashToInt(hramBin) + s.Mul(scalar, r) s.Sub(k, s). Mod(s, order) @@ -236,6 +239,12 @@ func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) // H ( R || m ) ?= r func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + // hFunc cannot be nil. + // We need a hash function for the Fiat-Shamir. + if hFunc == nil { + return false, errHashNeeded + } + // Deserialize the signature var sig Signature if _, err := sig.SetBytes(sigBin); err != nil { @@ -251,27 +260,23 @@ func (publicKey *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (boo var _P {{ .CurvePackage }}.G1Affine _P.FromJacobian(&P) - if hFunc != nil { - // compute H(R, M), all parameters in data are in Montgomery form - PX := _P.X.Bytes() - PY := _P.Y.Bytes() - sizeDataToHash := 2*sizeFp + len(message) - dataToHash := make([]byte, sizeDataToHash) - copy(dataToHash[:], PX[:]) - copy(dataToHash[sizeFp:], PY[:]) - copy(dataToHash[2*sizeFp:], message) - hFunc.Reset() - _, err := hFunc.Write(dataToHash[:]) - if err != nil { - return false, err - } - - hramBin := hFunc.Sum(nil) - e = HashToInt(hramBin) - } else { - e = HashToInt(message) + // compute H(R, M), all parameters in data are in Montgomery form + PX := _P.X.Bytes() + PY := _P.Y.Bytes() + sizeDataToHash := 2*sizeFp + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], PX[:]) + copy(dataToHash[sizeFp:], PY[:]) + copy(dataToHash[2*sizeFp:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return false, err } + hramBin := hFunc.Sum(nil) + e = HashToInt(hramBin) + return e.Cmp(r) == 0, nil } diff --git a/internal/generator/signature/schnorr/template/schnorr.test.go.tmpl b/internal/generator/signature/schnorr/template/schnorr.test.go.tmpl index 9f7293193..681c7fcf3 100644 --- a/internal/generator/signature/schnorr/template/schnorr.test.go.tmpl +++ b/internal/generator/signature/schnorr/template/schnorr.test.go.tmpl @@ -28,20 +28,6 @@ func TestSchnorr(t *testing.T) { }, )) - properties.Property("[{{ toUpper .Name }}] test the signing and verification (pre-hashed)", prop.ForAll( - func() bool { - - privKey, _ := GenerateKey(rand.Reader) - publicKey := privKey.PublicKey - - msg := []byte("testing Schnorr") - sig, _ := privKey.Sign(msg, nil) - flag, _ := publicKey.Verify(sig, msg, nil) - - return flag - }, - )) - properties.TestingRun(t, gopter.ConsoleReporter(false)) } @@ -53,9 +39,10 @@ func BenchmarkSignSchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") + hFunc := sha256.New() b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.Sign(msg, nil) + privKey.Sign(msg, hFunc) } } @@ -63,10 +50,11 @@ func BenchmarkVerifySchnorr(b *testing.B) { privKey, _ := GenerateKey(rand.Reader) msg := []byte("benchmarking Schnorr sign()") - sig, _ := privKey.Sign(msg, nil) + hFunc := sha256.New() + sig, _ := privKey.Sign(msg, hFunc) b.ResetTimer() for i := 0; i < b.N; i++ { - privKey.PublicKey.Verify(sig, msg, nil) + privKey.PublicKey.Verify(sig, msg, hFunc) } }