@ -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[:]) |
||||
|
} |
@ -0,0 +1,76 @@ |
|||||
|
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 := poseidon.New() |
||||
|
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 := decomrpessSig(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)) |
||||
|
} |
||||
|
|
||||
|
func decomrpessSig(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 |
||||
|
} |
@ -0,0 +1,53 @@ |
|||||
|
package poseidon |
||||
|
|
||||
|
import ( |
||||
|
"bytes" |
||||
|
"hash" |
||||
|
) |
||||
|
|
||||
|
type digest struct { |
||||
|
buf *bytes.Buffer |
||||
|
} |
||||
|
|
||||
|
// NewPoseidon returns the Poseidon hash of the input bytes.
|
||||
|
func NewPoseidon(b []byte) []byte { |
||||
|
h := New() |
||||
|
h.Write(b) |
||||
|
return h.Sum(nil) |
||||
|
} |
||||
|
|
||||
|
// New returns a new hash.Hash computing the Poseidon hash.
|
||||
|
func New() hash.Hash { |
||||
|
return &digest{ |
||||
|
buf: bytes.NewBuffer([]byte{}), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Write (via the embedded io.Writer interface) adds more data to the running hash.
|
||||
|
func (d *digest) Write(p []byte) (n int, err error) { |
||||
|
return d.buf.Write(p) |
||||
|
} |
||||
|
|
||||
|
// Sum returns the Poseidon checksum of the data.
|
||||
|
func (d *digest) Sum(b []byte) []byte { |
||||
|
hahs, err := HashBytes(d.buf.Bytes()) |
||||
|
if err != nil { |
||||
|
panic(err) |
||||
|
} |
||||
|
return append(b, hahs.Bytes()...) |
||||
|
} |
||||
|
|
||||
|
// Reset resets the Hash to its initial state.
|
||||
|
func (d *digest) Reset() { |
||||
|
d.buf.Reset() |
||||
|
} |
||||
|
|
||||
|
// Size returns the number of bytes Sum will return.
|
||||
|
func (d *digest) Size() int { |
||||
|
return 32 |
||||
|
} |
||||
|
|
||||
|
// BlockSize returns the hash block size.
|
||||
|
func (d *digest) BlockSize() int { |
||||
|
return spongeChunkSize |
||||
|
} |