Browse Source

Merge pull request #55 from iden3/feature/PID-676-support-golang-interfaces

PID-676: support hash interface for poseidon; support golang crypto interfaces…
fix/bbjj-err
Ilya 1 year ago
committed by GitHub
parent
commit
3fb23d780c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 702 additions and 0 deletions
  1. +81
    -0
      babyjub/babyjub_wrapper.go
  2. +65
    -0
      babyjub/babyjub_wrapper_test.go
  3. +13
    -0
      babyjub/helpers.go
  4. +60
    -0
      poseidon/poseidon_wrapper.go
  5. +483
    -0
      poseidon/poseidon_wrapper_test.go

+ 81
- 0
babyjub/babyjub_wrapper.go

@ -0,0 +1,81 @@
package babyjub
import (
"bytes"
"crypto"
"io"
"math/big"
)
// BjjWrappedPublicKey is a wrapper for PublicKey.
type BjjWrappedPublicKey struct {
pubKey *PublicKey
}
// Equal returns true if the public keys are equal.
func (pub *BjjWrappedPublicKey) Equal(x crypto.PublicKey) bool {
var xk *BjjWrappedPublicKey
switch x := x.(type) {
case BjjWrappedPublicKey:
xk = &x
case *BjjWrappedPublicKey:
xk = x
default:
return false
}
return pub.pubKey.X.Cmp(xk.pubKey.X) == 0 &&
pub.pubKey.Y.Cmp(xk.pubKey.Y) == 0
}
// BjjWrappedPrivateKey is a wrapper for PrivateKey.
type BjjWrappedPrivateKey struct {
privKey *PrivateKey
}
// NewBjjWrappedKey creates a new BjjWrappedPrivateKey.
func NewBjjWrappedKey(privKey *PrivateKey) *BjjWrappedPrivateKey {
return &BjjWrappedPrivateKey{privKey}
}
// RandomBjjWrappedKey creates a new BjjWrappedPrivateKey with a random private key.
func RandomBjjWrappedKey() *BjjWrappedPrivateKey {
privKey := NewRandPrivKey()
return NewBjjWrappedKey(&privKey)
}
// Public returns the public key of the private key.
func (w *BjjWrappedPrivateKey) Public() crypto.PublicKey {
return &BjjWrappedPublicKey{w.privKey.Public()}
}
// Sign signs the digest with the private key.
func (w *BjjWrappedPrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
hash := opts.HashFunc()
switch hash {
// alredy hashed
case crypto.Hash(0):
default:
hasher := hash.New()
hasher.Write(digest)
digest = hasher.Sum(nil)
}
digestBI := big.NewInt(0).SetBytes(digest)
sig := w.privKey.SignPoseidon(digestBI)
return sig.Compress().MarshalText()
}
// Equal returns true if the private keys are equal.
func (w *BjjWrappedPrivateKey) Equal(x crypto.PrivateKey) bool {
var xk *BjjWrappedPrivateKey
switch x := x.(type) {
case BjjWrappedPrivateKey:
xk = &x
case *BjjWrappedPrivateKey:
xk = x
default:
return false
}
return bytes.Equal(w.privKey[:], xk.privKey[:])
}

+ 65
- 0
babyjub/babyjub_wrapper_test.go

@ -0,0 +1,65 @@
package babyjub
import (
"crypto"
"crypto/rand"
"math/big"
"testing"
"github.com/iden3/go-iden3-crypto/poseidon"
"github.com/stretchr/testify/require"
)
// https://pkg.go.dev/crypto#PrivateKey
type shadowPrivateKey interface {
Public() crypto.PublicKey
Equal(x crypto.PrivateKey) bool
}
// https://pkg.go.dev/crypto#PublicKey
type shadowPublicKey interface {
Equal(x crypto.PublicKey) bool
}
func TestBjjWrappedPrivateKeyInterfaceImpl(t *testing.T) {
require.Implements(t, (*crypto.Signer)(nil), new(BjjWrappedPrivateKey))
require.Implements(t, (*shadowPrivateKey)(nil), new(BjjWrappedPrivateKey))
}
func TestBjjWrappedPrivateKey(t *testing.T) {
pk := RandomBjjWrappedKey()
hasher, err := poseidon.New(16)
require.NoError(t, err)
hasher.Write([]byte("test"))
digest := hasher.Sum(nil)
sig, err := pk.Sign(rand.Reader, digest, crypto.Hash(0))
require.NoError(t, err)
pub, ok := pk.Public().(*BjjWrappedPublicKey)
require.True(t, ok)
decomrpessSig, err := DecompressSig(sig)
require.NoError(t, err)
digestBI := big.NewInt(0).SetBytes(digest)
pub.pubKey.VerifyPoseidon(digestBI, decomrpessSig)
}
func TestBjjWrappedPrivateKeyEqual(t *testing.T) {
x1 := RandomBjjWrappedKey()
require.True(t, x1.Equal(x1))
x2 := RandomBjjWrappedKey()
require.False(t, x1.Equal(x2))
}
func TestBjjWrappedPublicKeyInterfaceImpl(t *testing.T) {
require.Implements(t, (*shadowPublicKey)(nil), new(BjjWrappedPublicKey))
}
func TestBjjWrappedPublicKeyEqual(t *testing.T) {
x1 := RandomBjjWrappedKey().Public().(*BjjWrappedPublicKey)
require.True(t, x1.Equal(x1))
x2 := RandomBjjWrappedKey().Public()
require.False(t, x1.Equal(x2))
}

+ 13
- 0
babyjub/helpers.go

@ -18,3 +18,16 @@ func Blake512(m []byte) []byte {
} }
return h.Sum(nil) return h.Sum(nil)
} }
// DecompressSig decompresses a compressed signature.
func DecompressSig(commpresedSig []byte) (*Signature, error) {
poseidonComSig := &SignatureComp{}
if err := poseidonComSig.UnmarshalText(commpresedSig); err != nil {
return nil, err
}
poseidonDecSig, err := poseidonComSig.Decompress()
if err != nil {
return nil, err
}
return poseidonDecSig, nil
}

+ 60
- 0
poseidon/poseidon_wrapper.go

@ -0,0 +1,60 @@
package poseidon
import (
"bytes"
"errors"
"hash"
)
type hasher struct {
buf *bytes.Buffer
frameSize int
}
// Sum returns the Poseidon hash of the input bytes.
// use frame size of 16 inputs by default
func Sum(b []byte) []byte {
h, _ := New(16)
h.Write(b)
return h.Sum(nil)
}
// New returns a new hash.Hash computing the Poseidon hash.
func New(frameSize int) (hash.Hash, error) {
if frameSize < 2 || frameSize > 16 {
return nil, errors.New("incorrect frame size")
}
return &hasher{
buf: bytes.NewBuffer([]byte{}),
frameSize: frameSize,
}, nil
}
// Write (via the embedded io.Writer interface) adds more data to the running hash.
func (h *hasher) Write(p []byte) (n int, err error) {
return h.buf.Write(p)
}
// Sum returns the Poseidon digest of the data.
func (h *hasher) Sum(b []byte) []byte {
hahs, err := HashBytesX(h.buf.Bytes(), h.frameSize)
if err != nil {
panic(err)
}
return append(b, hahs.Bytes()...)
}
// Reset resets the Hash to its initial state.
func (h *hasher) Reset() {
h.buf.Reset()
}
// Size returns the number of bytes Sum will return.
func (h *hasher) Size() int {
return 32
}
// BlockSize returns the hash block size.
func (h *hasher) BlockSize() int {
return spongeChunkSize
}

+ 483
- 0
poseidon/poseidon_wrapper_test.go
File diff suppressed because it is too large
View File


Loading…
Cancel
Save