// ReadPubKey will read the file and decrypt the public key inside // It takes a suite to decrypt and a file name // Returns the public key, whatever text is in front and an error if anything went wrong func ReadPubKey(suite abstract.Suite, fileName string) (abstract.Point, string, error) { public := suite.Point() // Opening files pubFile, err := os.Open(fileName) if err != nil { return nil, "", err } defer pubFile.Close() // read the string before by, err := ioutil.ReadAll(pubFile) if err != nil { return nil, "", errors.New(fmt.Sprintf("Error reading the whole file %s", err)) } splits := strings.Split(string(by), " ") if len(splits) != 2 { return nil, "", errors.New(fmt.Sprintf("Error reading pub key file format is not correct (val space val)")) } before := splits[0] key := strings.NewReader(splits[1]) // Some readings public, err = ReadPub64(suite, key) if err != nil { return nil, "", errors.New(fmt.Sprintf("Error reading the public key itself: %s", err)) } return public, before, nil }
func benchSign(suite abstract.Suite, pub []abstract.Point, pri abstract.Secret, niter int) { rand := suite.Cipher([]byte("example")) for i := 0; i < niter; i++ { Sign(suite, rand, benchMessage, Set(pub), nil, 0, pri) } }
// ShuffleDecrypt performs a shuffle and partial decyption of the given ciphertexts, producing correctness // proofs in the process func ShuffleDecrypt(suite abstract.Suite, ciphertexts []*elgamal.CipherText, pks []*elgamal.PubKey, sk *elgamal.PriKey, nonce string, position int) (*VerifiableShuffle, error) { amount := len(ciphertexts) if amount == 0 { panic("Can't shuffle 0 ciphertexts") } c1, c2 := elgamal.Unpack(ciphertexts) // The ciphertexts are encrypted against these public keys; it still includes ours // The proof of the shuffle will also be w.r.t. this public key sumpk := elgamal.SumKeys(pks[position:]) // Do the shuffle, create a proof of its correctness shuffledC1, shuffledC2, prover := shuffle.Shuffle(suite, sumpk.Base, sumpk.Key, c1, c2, suite.Cipher(nil)) shuffleProof, err := proof.HashProve(suite, "ElGamalShuffle"+nonce, suite.Cipher(nil), prover) if err != nil { return nil, err } shuffled := elgamal.Pack(shuffledC1, shuffledC2) // Do the partial decryption, create a proof of its correctness decryptionProofs, decrypted := make([][]byte, amount), make([]*elgamal.CipherText, amount) for i := range shuffledC1 { decrypted[i], decryptionProofs[i], err = sk.PartialProofDecrypt(shuffled[i], nonce) if err != nil { return nil, err } } return &VerifiableShuffle{shuffled, decrypted, decryptionProofs, shuffleProof}, nil }
func ElGamalVerify(suite abstract.Suite, message []byte, publicKey abstract.Point, signatureBuffer []byte, g abstract.Point) 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(g, 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 }
// Create new signing node that incorporates a given private key func NewKeyedNode(hn coconet.Host, suite abstract.Suite, PrivKey abstract.Secret) *Node { sn := &Node{Host: hn, suite: suite, PrivKey: PrivKey} sn.PubKey = suite.Point().Mul(nil, sn.PrivKey) sn.peerKeys = make(map[string]abstract.Point) sn.closed = make(chan error, 20) sn.done = make(chan int, 10) sn.commitsDone = make(chan int, 10) sn.viewChangeCh = make(chan string, 0) sn.RoundCommits = make(map[int][]*SigningMessage) sn.RoundResponses = make(map[int][]*SigningMessage) sn.FailureRate = 0 h := fnv.New32a() h.Write([]byte(hn.Name())) seed := h.Sum32() sn.Rand = rand.New(rand.NewSource(int64(seed))) sn.Host.SetSuite(suite) sn.VoteLog = NewVoteLog() sn.Actions = make(map[int][]*Vote) sn.RoundsPerView = 0 sn.Rounds = make(map[int]Round) sn.MaxWait = 50 * time.Second return sn }
// Decrypt a message encrypted for a particular anonymity set. // Returns the cleartext message on success, or an error on failure. // // The caller provides the anonymity set for which the message is intended, // and the private key corresponding to one of the public keys in the set. // Decrypt verifies that the message is encrypted correctly for this set - // in particular, that it could be decrypted by ALL of the listed members - // before returning successfully with the decrypted message. // This verification ensures that a malicious sender // cannot de-anonymize a receiver by constructing a ciphertext incorrectly // so as to be decryptable by only some members of the set. // As a side-effect, this verification also ensures plaintext-awareness: // that is, it is infeasible for a sender to construct any ciphertext // that will be accepted by the receiver without knowing the plaintext. // func Decrypt(suite abstract.Suite, ciphertext []byte, anonymitySet Set, mine int, privateKey abstract.Secret, hide bool) ([]byte, error) { // Decrypt and check the encrypted key-header. xb, hdrlen, err := decryptKey(suite, ciphertext, anonymitySet, mine, privateKey, hide) if err != nil { return nil, err } // Determine the message layout cipher := suite.Cipher(xb) maclen := cipher.KeySize() if len(ciphertext) < hdrlen+maclen { return nil, errors.New("ciphertext too short") } hdrhi := hdrlen msghi := len(ciphertext) - maclen // Decrypt the message and check the MAC ctx := ciphertext[hdrhi:msghi] mac := ciphertext[msghi:] msg := make([]byte, len(ctx)) cipher.Message(msg, ctx, ctx) cipher.Partial(mac, mac, nil) if subtle.ConstantTimeAllEq(mac, 0) == 0 { return nil, errors.New("invalid ciphertext: failed MAC check") } return msg, nil }
func verifyMessage(suite abstract.Suite, m interface{}, hash1 []byte) error { // Make a copy of the signature x := reflect.ValueOf(m).Elem().FieldByName("Sig") sig := reflect.New(x.Type()).Elem() sig.Set(x) // Reset signature field reflect.ValueOf(m).Elem().FieldByName("Sig").Set(reflect.ValueOf(crypto.SchnorrSig{})) // XXX: hack // Marshal ... mb, err := network.MarshalRegisteredType(m) if err != nil { return err } // ... and hash message hash2, err := crypto.HashBytes(suite.Hash(), mb) if err != nil { return err } // Copy back original signature reflect.ValueOf(m).Elem().FieldByName("Sig").Set(sig) // XXX: hack // Compare hashes if !bytes.Equal(hash1, hash2) { return errors.New("Message has a different hash than the given one") } return nil }
func NewNode(hn coconet.Host, suite abstract.Suite, random cipher.Stream) *Node { sn := &Node{Host: hn, suite: suite} msgSuite = suite sn.PrivKey = suite.Secret().Pick(random) sn.PubKey = suite.Point().Mul(nil, sn.PrivKey) sn.peerKeys = make(map[string]abstract.Point) sn.Rounds = make(map[int]*Round) sn.closed = make(chan error, 20) sn.done = make(chan int, 10) sn.commitsDone = make(chan int, 10) sn.viewChangeCh = make(chan string, 0) sn.FailureRate = 0 h := fnv.New32a() h.Write([]byte(hn.Name())) seed := h.Sum32() sn.Rand = rand.New(rand.NewSource(int64(seed))) sn.Host.SetSuite(suite) sn.VoteLog = NewVoteLog() sn.Actions = make(map[int][]*Vote) sn.RoundsPerView = 100 return sn }
// Retrieve an object in a Merkle tree, // validating the entire path in the process. // Returns a slice of a buffer obtained from HashGet.Get(), // which might be shared and should be considered read-only. func MerkleGet(suite abstract.Suite, root []byte, path MerklePath, ctx HashGet) ([]byte, error) { // Follow pointers through intermediate levels blob := root for i := range path.Ptr { beg := path.Ptr[i] end := beg + suite.HashLen() if end > len(blob) { return nil, errors.New("bad Merkle tree pointer offset") } id := HashId(blob[beg:end]) b, e := ctx.Get(id) // Lookup the next-level blob if e != nil { return nil, e } blob = b } // Validate and extract the actual object beg := path.Ofs end := beg + path.Len if end > len(blob) { return nil, errors.New("bad Merkle tree object offset/length") } return blob[beg:end], nil }
func NewFile(suite abstract.Suite, path string) (*File, error) { f, err := os.Open(path) if err != nil { log.Fatal("Failed opening file", path, err) } defer f.Close() fi, err := f.Stat() if err != nil { return nil, err } blocks := (fi.Size() + BlockSize - 1) / BlockSize x := &File{ Name: path, Hashes: make(map[string]int64, blocks), } for i := 0; int64(i) < blocks; i++ { tmp := make([]byte, BlockSize) _, err := f.Read(tmp) if err != nil { log.Fatal("Failed reading file", err) } h := suite.Hash() h.Write(tmp) x.Hashes[string(h.Sum(nil))] = int64((i * BlockSize)) } return x, nil }
// DefaultConstructors gives a default constructor for protobuf out of the global suite func DefaultConstructors(suite abstract.Suite) protobuf.Constructors { constructors := make(protobuf.Constructors) var point abstract.Point var secret abstract.Scalar constructors[reflect.TypeOf(&point).Elem()] = func() interface{} { return suite.Point() } constructors[reflect.TypeOf(&secret).Elem()] = func() interface{} { return suite.Scalar() } return constructors }
func newHashProver(suite abstract.Suite, protoName string, rand abstract.Cipher) *hashProver { var sc hashProver sc.suite = suite sc.pubrand = suite.Cipher([]byte(protoName)) sc.prirand = rand return &sc }
func ElGamalDecrypt(suite abstract.Suite, prikey abstract.Secret, K, C abstract.Point) ( M abstract.Point) { // ElGamal-decrypt the ciphertext (K,C) to reproduce the message. S := suite.Point().Mul(K, prikey) // regenerate shared secret M = suite.Point().Sub(C, S) // use to un-blind the message return }
// VerifySignature verifies if the challenge and the secret (from the response phase) form a // correct signature for this message using the aggregated public key. func VerifySignature(suite abstract.Suite, msg []byte, public abstract.Point, challenge, secret abstract.Scalar) error { // recompute the challenge and check if it is the same commitment := suite.Point() commitment = commitment.Add(commitment.Mul(nil, secret), suite.Point().Mul(public, challenge)) return verifyCommitment(suite, msg, commitment, challenge) }
func ElGamalDecrypt(suite abstract.Suite, prikey abstract.Secret, K, C abstract.Point) ( message []byte, err error) { // ElGamal-decrypt the ciphertext (K,C) to reproduce the message. S := suite.Point().Mul(K, prikey) // regenerate shared secret M := suite.Point().Sub(C, S) // use to un-blind the message message, err = M.Data() // extract the embedded data return }
// Read a secret in hexadceimal from string func ReadSecretHex(suite abstract.Suite, str string) (abstract.Secret, error) { enc, err := hex.DecodeString(str) if err != nil { return nil, err } sec := suite.Secret() err = sec.UnmarshalBinary(enc) return sec, err }
/* The servergenerateresponse function is fairly self explanatory - this function provides an answer to the challenge message provided by the user. */ func ServerGenerateResponse(suite abstract.Suite, challenge WISchnorrChallengeMessage, privateParameters WISchnorrBlindPrivateParams, privKey SchnorrKeyset) WISchnorrResponseMessage { c := suite.Secret() c.Sub(challenge.E, privateParameters.D) r := suite.Secret() r.Mul(c, privKey.X).Sub(privateParameters.U, r) return WISchnorrResponseMessage{r, c, privateParameters.S, privateParameters.D} }
// ReadScalarHex reads a scalar in hexadecimal from string func ReadScalarHex(suite abstract.Suite, str string) (abstract.Scalar, error) { enc, err := hex.DecodeString(str) if err != nil { return nil, err } s := suite.Scalar() err = s.UnmarshalBinary(enc) return s, err }
// ReadPubHex reads a hexadecimal representation of a public point and convert it to the // right struct func ReadPubHex(suite abstract.Suite, s string) (abstract.Point, error) { encoded, err := hex.DecodeString(s) if err != nil { return nil, err } point := suite.Point() err = point.UnmarshalBinary(encoded) return point, err }
// generate keys for the tree func (t *Tree) GenKeys(suite abstract.Suite, rand abstract.Cipher) { t.TraverseTree(func(t *Tree) { PrivKey := suite.Secret().Pick(rand) PubKey := suite.Point().Mul(nil, PrivKey) prk, _ := PrivKey.MarshalBinary() pbk, _ := PubKey.MarshalBinary() t.PriKey = string(hex.EncodeToString(prk)) t.PubKey = string(hex.EncodeToString(pbk)) }) }
// GetSharedSecret returns the shared secret, as in the Verdict hash-based construction, for the given public and // private keys func GetSharedSecret(pk *PubKey, sk *PriKey) (abstract.Secret, abstract.Point) { var suite abstract.Suite suite = crypto.Suite point := suite.Point().Mul(pk.Elem, sk.secret) r := crypto.HashKDF(point) R := suite.Point().Mul(crypto.Generator, r) return r, R }
func signH1pre(suite abstract.Suite, linkScope []byte, linkTag abstract.Point, message []byte) abstract.Cipher { H1pre := suite.Cipher(message) // m if linkScope != nil { H1pre.Write(linkScope) // L tag, _ := linkTag.MarshalBinary() H1pre.Write(tag) // ~y } return H1pre }
// Verify checks a signature generated by Sign. // // The caller provides the message, anonymity set, and linkage scope // with which the signature was purportedly produced. // If the signature is a valid linkable signature (linkScope != nil), // this function returns a linkage tag that uniquely corresponds // to the signer within the given linkScope. // If the signature is a valid unlinkable signature (linkScope == nil), // returns an empty but non-nil byte-slice instead of a linkage tag on success. // Returns a nil linkage tag and an error if the signature is invalid. func Verify(suite abstract.Suite, message []byte, anonymitySet Set, linkScope []byte, signatureBuffer []byte) ([]byte, error) { n := len(anonymitySet) // anonymity set size L := []abstract.Point(anonymitySet) // public keys in ring // Decode the signature buf := bytes.NewBuffer(signatureBuffer) var linkBase, linkTag abstract.Point sig := lSig{} sig.S = make([]abstract.Secret, n) if linkScope != nil { // linkable ring signature if err := abstract.Read(buf, &sig, suite); err != nil { return nil, err } linkStream := suite.Cipher(linkScope) linkBase, _ = suite.Point().Pick(nil, linkStream) linkTag = sig.Tag } else { // unlinkable ring signature if err := abstract.Read(buf, &sig.uSig, suite); err != nil { return nil, err } } // Pre-hash the ring-position-invariant parameters to H1. H1pre := signH1pre(suite, linkScope, linkTag, message) // Verify the signature var P, PG, PH abstract.Point P = suite.Point() PG = suite.Point() if linkScope != nil { PH = suite.Point() } s := sig.S ci := sig.C0 for i := 0; i < n; i++ { PG.Add(PG.Mul(nil, s[i]), P.Mul(L[i], ci)) if linkScope != nil { PH.Add(PH.Mul(linkBase, s[i]), P.Mul(linkTag, ci)) } ci = signH1(suite, H1pre, PG, PH) } if !ci.Equal(sig.C0) { return nil, errors.New("invalid signature") } // Return the re-encoded linkage tag, for uniqueness checking if linkScope != nil { tag, _ := linkTag.MarshalBinary() return tag, nil } else { return []byte{}, nil } }
// Checks the signature against // the message func SchnorrVerify(suite abstract.Suite, kp SchnorrPublicKey, msg []byte, sig []byte) (bool, error) { buf := bytes.NewBuffer(sig) signature := SchnorrSignature{} err := abstract.Read(buf, &signature, suite) if err != nil { return false, err } s := signature.S e := signature.E var gs, ye, r abstract.Point gs = suite.Point().Mul(nil, s) // g^s ye = suite.Point().Mul(kp.Y, e) // y^e r = suite.Point().Add(gs, ye) // g^xy^e r_bin, _ := r.MarshalBinary() msg_and_r := append(msg, r_bin...) hasher := sha3.New256() hasher.Write(msg_and_r) h := hasher.Sum(nil) // again I'm hoping this just reads the state out // and doesn't actually perform any ops lct := suite.Cipher(h) ev := suite.Secret().Pick(lct) return ev.Equal(e), nil }
// computeSubtreeAggregate will compute the aggregate subtree public key for // each node of the tree. // root is the root of the subtree we want to compute the aggregate for // recursive function so it will go down to the leaves then go up to the root // Return the aggregate sub tree public key for this root (and compute each sub // aggregate public key for each of the children). func (t *Tree) computeSubtreeAggregate(suite abstract.Suite, root *TreeNode) abstract.Point { aggregate := suite.Point().Add(suite.Point().Null(), root.ServerIdentity.Public) // DFS search for _, ch := range root.Children { aggregate = aggregate.Add(aggregate, t.computeSubtreeAggregate(suite, ch)) } // sets the field root.PublicAggregateSubTree = aggregate return aggregate }
func signH1(suite abstract.Suite, H1pre abstract.Cipher, PG, PH abstract.Point) abstract.Secret { H1 := H1pre.Clone() PGb, _ := PG.MarshalBinary() H1.Write(PGb) if PH != nil { PHb, _ := PH.MarshalBinary() H1.Write(PHb) } H1.Message(nil, nil, nil) // finish message absorption return suite.Secret().Pick(H1) }
// (Server side) This function reads the collective challenge // from the wire, generates and serializes a response // to that as a raw "secret" func SchnorrMUnmarshallCCComputeResponse(suite abstract.Suite, kv SchnorrKeyset, privatecommit SchnorrMPrivateCommitment, cc []byte) SchnorrMResponse { hct := suite.Cipher(cc) c := suite.Secret().Pick(hct) r := suite.Secret() r.Mul(c, kv.X).Sub(privatecommit.V, r) return SchnorrMResponse{r} }
func newHashVerifier(suite abstract.Suite, protoName string, proof []byte) *hashVerifier { var c hashVerifier if _, err := c.proof.Write(proof); err != nil { panic("Buffer.Write failed") } c.suite = suite c.prbuf = c.proof.Bytes() c.pubrand = suite.Cipher([]byte(protoName)) return &c }
func hash(suite abstract.Suite, r abstract.Point, msg []byte) (abstract.Scalar, error) { rBuf, err := r.MarshalBinary() if err != nil { return nil, err } cipher := suite.Cipher(rBuf) cipher.Message(nil, nil, msg) // (re)compute challenge (e) e := suite.Scalar().Pick(cipher) return e, nil }
func newHost(suite abstract.Suite, rand cipher.Stream, hostname string) *host { h := &host{} h.name = hostname h.log.init(suite) h.pri = suite.Secret().Pick(rand) h.pub = suite.Point().Mul(nil, h.pri) h.id = abstract.HashBytes(suite, h.pub.Encode()) h.peers = make(map[string]*peer) h.trees = make(map[string]*treeNode) return h }