arnaucube
arnaucube/go-blindsecp256k1Public Self-hosted repository
Add Signature Compression & Decompression
arnaucube root@arnaucube.com
Tue, 23 Mar 2021 17:24:13 +0100
commit

ccaa6313370dddc0923271bd1844baa4750672ba

parent

8b985dba31c07a4962c0953d812144f59785bf99

5 files changed, 88 insertions(+), 11 deletions(-)

jump to
M .github/workflows/lint.yml → .github/workflows/lint.yml

@@ -14,4 +14,4 @@ - name: Lint

run: | curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.30.0 rm -r wasm - $(go env GOPATH)/bin/golangci-lint run --timeout=5m -c .golangci.yml + go list -f '{{.Dir}}' ./... | fgrep -v wasm | xargs realpath --relative-to=. | xargs $(go env GOPATH)/bin/golangci-lint run --timeout=5m -c .golangci.yml
M README.md → README.md

@@ -7,17 +7,24 @@

## Usage ```go +import ( + [...] + "github.com/arnaucube/go-blindsecp256k1" +) + +[...] + // signer: create new signer key pair -sk := NewPrivateKey() +sk := blindsecp256k1.NewPrivateKey() signerPubK := sk.Public() // signer: when user requests new R parameter to blind a new msg, // create new signerR (public) with its secret k -k, signerR := NewRequestParameters() +k, signerR := blindsecp256k1.NewRequestParameters() // user: blinds the msg using signer's R msg := new(big.Int).SetBytes([]byte("test")) -msgBlinded, userSecretData, err := Blind(msg, signerR) +msgBlinded, userSecretData, err := blindsecp256k1.Blind(msg, signerR) require.Nil(t, err) // signer: signs the blinded message using its private key & secret k

@@ -25,10 +32,10 @@ sBlind, err := sk.BlindSign(msgBlinded, k)

require.Nil(t, err) // user: unblinds the blinded signature -sig := Unblind(sBlind, userSecretData) +sig := blindsecp256k1.Unblind(sBlind, userSecretData) // signature can be verified with signer PublicKey -verified := Verify(msg, sig, signerPubK) +verified := blindsecp256k1.Verify(msg, sig, signerPubK) assert.True(t, verified) ```
M blindsecp256k1.go → blindsecp256k1.go

@@ -86,7 +86,7 @@ }

return nil } -// Compress packs a Point to a byte array of 33 bytes +// Compress packs a Point to a byte array of 33 bytes, encoded in little-endian. func (p *Point) Compress() [33]byte { xBytes := p.X.Bytes() odd := byte(0)

@@ -262,6 +262,30 @@ // Signature contains the signature values S & F

type Signature struct { S *big.Int F *Point +} + +// Compress packs a Signature to a byte array of 65 bytes, encoded in +// little-endian. +func (s *Signature) Compress() [65]byte { + var b [65]byte + sBytes := s.S.Bytes() + fBytes := s.F.Compress() + copy(b[:32], swapEndianness(sBytes)) + copy(b[32:], fBytes[:]) + return b +} + +// DecompressSignature unpacks a Signature from the given byte array of 65 bytes +func DecompressSignature(b [65]byte) (*Signature, error) { + s := new(big.Int).SetBytes(swapEndianness(b[:32])) + var fBytes [33]byte + copy(fBytes[:], b[32:]) + f, err := DecompressPoint(fBytes) + if err != nil { + return nil, err + } + sig := &Signature{S: s, F: f} + return sig, nil } // Unblind performs the unblinding operation of the blinded signature for the
M blindsecp256k1_test.go → blindsecp256k1_test.go

@@ -107,6 +107,51 @@ assert.Equal(t, p, p2)

} } +func TestSignatureCompressDecompress(t *testing.T) { + f := G + sig := &Signature{ + S: big.NewInt(1), + F: f, + } + b := sig.Compress() + assert.Equal(t, + "01000000000000000000000000000000000000000000000000000000000000007"+ + "9be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179800", + hex.EncodeToString(b[:])) + sig2, err := DecompressSignature(b) + require.Nil(t, err) + assert.Equal(t, sig, sig2) + + f = G + sig = &Signature{ + S: Q, + F: f, + } + b = sig.Compress() + assert.Equal(t, + "0cffffbfffffffffffffffffffffffffffffffffffffffffffffffffffffff3f7"+ + "9be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179800", + hex.EncodeToString(b[:])) + sig2, err = DecompressSignature(b) + require.Nil(t, err) + require.Equal(t, sig, sig2) + + for i := 2; i < 10; i++ { + s := new(big.Int).Mod(new(big.Int).Mul(Q, big.NewInt(int64(i))), P) + f := G.Mul(big.NewInt(int64(i))) + sig := &Signature{ + S: s, + F: f, + } + b := sig.Compress() + assert.Equal(t, 65, len(b)) + + sig2, err := DecompressSignature(b) + require.Nil(t, err) + assert.Equal(t, sig, sig2) + } +} + func BenchmarkCompressDecompress(b *testing.B) { const n = 256 var points [n]*Point
M parsers.go → parsers.go

@@ -65,9 +65,9 @@ // 64 which has encoded the point coordinates each one as 32 bytes in

// little-endian. func NewPointFromBytes(b []byte) (*Point, error) { if len(b) != 64 { //nolint:gomnd - return nil, - fmt.Errorf("Can not parse bytes to Point, expected byte array of length %d, current %d", - 64, len(b)) + return nil, fmt.Errorf("Can not parse bytes to Point,"+ + " expected byte array of length %d, current %d", + 64, len(b)) } p := &Point{} p.X = new(big.Int).SetBytes(swapEndianness(b[:32]))

@@ -193,7 +193,8 @@ // bytes in little-endian.

func NewSignatureFromBytes(b []byte) (*Signature, error) { if len(b) != 96 { //nolint:gomnd return nil, - fmt.Errorf("Can not parse bytes to Signature, expected byte array of length %d, current %d", + fmt.Errorf("Can not parse bytes to Signature,"+ + " expected byte array of length %d, current %d", 96, len(b)) } s := new(big.Int).SetBytes(swapEndianness(b[:32]))