Repository navigation
Expand file tree
/
Copy pathsig_test.go
More file actions
114 lines (95 loc) · 3.12 KB
/
Copy pathsig_test.go
File metadata and controls
114 lines (95 loc) · 3.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package crypto
import (
"bytes"
"crypto/cipher"
"encoding/hex"
"errors"
"fmt"
"github.com/dedis/crypto/abstract"
"github.com/dedis/crypto/openssl"
)
// A basic, verifiable signature
type basicSig struct {
C abstract.Secret // challenge
R abstract.Secret // response
}
// Returns a secret that depends on on a message and a point
func hashElGamal(suite abstract.Suite, message []byte, p abstract.Point) abstract.Secret {
H := suite.Hash()
H.Write(message)
H.Write(p.Encode())
b := H.Sum(nil)
s := suite.Stream(b[:suite.KeyLen()])
return suite.Secret().Pick(s)
}
// This simplified implementation of ElGamal Signatures is based on
// crypto/anon/sig.go
// The ring structure is removed and
// The anonimity set is reduced to one public key = no anonimity
func ElGamalSign(suite abstract.Suite, random cipher.Stream, message []byte,
privateKey abstract.Secret) []byte {
// Create random secret v and public point commitment T
v := suite.Secret().Pick(random)
T := suite.Point().Mul(nil, v)
// Create challenge c based on message and T
c := hashElGamal(suite, message, T)
// Compute response r = v - x*c
r := suite.Secret()
r.Mul(privateKey, c).Sub(v, r)
// Return verifiable signature {c, r}
// Verifier will be able to compute v = r + x*c
// And check that hashElgamal for T and the message == c
buf := bytes.Buffer{}
sig := basicSig{c, r}
abstract.Write(&buf, &sig, suite)
return buf.Bytes()
}
func ElGamalVerify(suite abstract.Suite, message []byte, publicKey abstract.Point,
signatureBuffer []byte) error {
// Decode the signature
buf := bytes.NewBuffer(signatureBuffer)
sig := basicSig{}
if err := abstract.Read(buf, &sig, suite); err != nil {
return err
}
r := sig.R
c := sig.C
// Compute base**(r + x*c) == T
var P, T abstract.Point
P = suite.Point()
T = suite.Point()
T.Add(T.Mul(nil, r), P.Mul(publicKey, c))
// Verify that the hash based on the message and T
// matches the challange c from the signature
c = hashElGamal(suite, message, T)
if !c.Equal(sig.C) {
return errors.New("invalid signature")
}
return nil
}
// Example of using ElGamal
func ExampleElGamal() {
// Crypto setup
suite := openssl.NewAES128SHA256P256()
rand := abstract.HashStream(suite, []byte("example"), nil)
// Create a public/private keypair (X,x)
x := suite.Secret().Pick(rand) // create a private key x
X := suite.Point().Mul(nil, x) // corresponding public key X
// Generate the signature
M := []byte("Hello World!") // message we want to sign
sig := ElGamalSign(suite, rand, M, x)
fmt.Print("Signature:\n" + hex.Dump(sig))
// Verify the signature against the correct message
err := ElGamalVerify(suite, M, X, sig)
if err != nil {
panic(err.Error())
}
fmt.Println("Signature verified against correct message.")
// Output:
// Signature:
// 00000000 ea 1b 94 c6 31 8a 90 22 2c 05 a3 e7 6f fe 31 8e |....1..",...o.1.|
// 00000010 e4 19 f7 3f 9e 28 b2 73 40 89 a0 1a f6 73 b1 20 |...?.(.s@....s. |
// 00000020 c7 34 3f 18 9c ad 46 5b f7 1e 62 b2 21 e9 91 43 |.4?...F[..b.!..C|
// 00000030 40 33 94 ef 0b 8e e5 fa 90 02 de 9a e3 a5 ee 9e |@3..............|
// Signature verified against correct message.
}