Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zero knowledge for discrete log #367

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ go 1.17
require (
github.com/bwesterb/go-ristretto v1.2.2
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ github.com/bwesterb/go-ristretto v1.2.2/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7N
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand Down
8 changes: 8 additions & 0 deletions math/polynomial/polynomial.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ func (p Polynomial) Evaluate(x group.Scalar) group.Scalar {
return px
}

func (p Polynomial) Coefficients() []group.Scalar {
c := make([]group.Scalar, len(p.c))
for i := range p.c {
c[i] = p.c[i].Copy()
}
return c
}

// LagrangePolynomial stores a Lagrange polynomial over the set of scalars of a group.
type LagrangePolynomial struct {
// Internal representation is in Lagrange basis:
Expand Down
36 changes: 36 additions & 0 deletions ot/simplestOT/simplestOT.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Reference: https://eprint.iacr.org/2015/267.pdf (1 out of 2 OT case)
// Sender has 2 messages m0, m1
// Receiver receives mc based on the choice bit c

package simplestOT

import (
"github.com/cloudflare/circl/group"
)

// Input: myGroup, the group we operate in
// Input: m0, m1 the 2 message of the sender
// Input: choice, the bit c of the receiver
// Input: index, the index of this BaseOT
func BaseOT(myGroup group.Group, sender *SenderSimOT, receiver *ReceiverSimOT, m0, m1 []byte, choice, index int) error {

// Initialization
A := sender.InitSender(myGroup, m0, m1, index)

// Round 1
// Sender sends A to receiver
B := receiver.Round1Receiver(myGroup, choice, index, A)

// Round 2
// Receiver sends B to sender
e0, e1 := sender.Round2Sender(B)

// Round 3
// Sender sends e0 e1 to receiver
errDec := receiver.Round3Receiver(e0, e1, receiver.c)
if errDec != nil {
return errDec
}

return nil
}
240 changes: 240 additions & 0 deletions ot/simplestOT/simplestOTLocal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
package simplestOT

import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/subtle"
"errors"
"io"

"github.com/cloudflare/circl/group"
"golang.org/x/crypto/sha3"
)

const keyLength = 16

// AES GCM encryption, we don't need to pad because our input is fixed length
// Need to use authenticated encryption to defend against tampering on ciphertext
// Input: key, plaintext message
// Output: ciphertext
func aesEncGCM(key, plaintext []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}

aesgcm, err := cipher.NewGCM(block)
if err != nil {
panic(err.Error())
}

nonce := make([]byte, aesgcm.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
panic(err)
}

ciphertext := aesgcm.Seal(nonce, nonce, plaintext, nil)
return ciphertext
}

// AES GCM decryption
// Input: key, ciphertext message
// Output: plaintext
func aesDecGCM(key, ciphertext []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
panic(err.Error())
}
nonceSize := aesgcm.NonceSize()
if len(ciphertext) < nonceSize {
return nil, errors.New("ciphertext too short")
}

nonce, encryptedMessage := ciphertext[:nonceSize], ciphertext[nonceSize:]

plaintext, err := aesgcm.Open(nil, nonce, encryptedMessage, nil)

return plaintext, err
}

// Initialization

// Input: myGroup, the group we operate in
// Input: m0, m1 the 2 message of the sender
// Input: index, the index of this BaseOT
// Output: A = [a]G, a the sender randomness
func (sender *SenderSimOT) InitSender(myGroup group.Group, m0, m1 []byte, index int) group.Element {
sender.a = myGroup.RandomNonZeroScalar(rand.Reader)
sender.k0 = make([]byte, keyLength)
sender.k1 = make([]byte, keyLength)
sender.m0 = m0
sender.m1 = m1
sender.index = index
sender.A = myGroup.NewElement()
sender.A.MulGen(sender.a)
sender.myGroup = myGroup
return sender.A.Copy()
}

// Round 1

// ---- sender should send A to receiver ----

// Input: myGroup, the group we operate in
// Input: choice, the receiver choice bit
// Input: index, the index of this BaseOT
// Input: A, from sender
// Output: B = [b]G if c == 0, B = A+[b]G if c == 1 (Implementation in constant time). b, the receiver randomness
func (receiver *ReceiverSimOT) Round1Receiver(myGroup group.Group, choice int, index int, A group.Element) group.Element {
receiver.b = myGroup.RandomNonZeroScalar(rand.Reader)
receiver.c = choice
receiver.kR = make([]byte, keyLength)
receiver.index = index
receiver.A = A
receiver.myGroup = myGroup

bG := myGroup.NewElement()
bG.MulGen(receiver.b)
cScalar := myGroup.NewScalar()
cScalar.SetUint64(uint64(receiver.c))
add := receiver.A.Copy()
add.Mul(receiver.A, cScalar)
receiver.B = myGroup.NewElement()
receiver.B.Add(bG, add)

return receiver.B.Copy()
}

// Round 2

// ---- receiver should send B to sender ----

// Input: B from the receiver
// Output: e0, e1, encryption of m0 and m1 under key k0, k1
func (sender *SenderSimOT) Round2Sender(B group.Element) ([]byte, []byte) {
sender.B = B

aB := sender.myGroup.NewElement()
aB.Mul(sender.B, sender.a)
maA := sender.myGroup.NewElement()
maA.Mul(sender.A, sender.a)
maA.Neg(maA)
aBaA := sender.myGroup.NewElement()
aBaA.Add(aB, maA)

// Hash the whole transcript A|B|...
AByte, errByte := sender.A.MarshalBinary()
if errByte != nil {
panic(errByte)
}
BByte, errByte := sender.B.MarshalBinary()
if errByte != nil {
panic(errByte)
}
aBByte, errByte := aB.MarshalBinary()
if errByte != nil {
panic(errByte)
}
hashByte0 := append(AByte, BByte...)
hashByte0 = append(hashByte0, aBByte...)

s := sha3.NewShake128()
_, errWrite := s.Write(hashByte0)
if errWrite != nil {
panic(errWrite)
}
_, errRead := s.Read(sender.k0)
if errRead != nil {
panic(errRead)
}

aBaAByte, errByte := aBaA.MarshalBinary()
if errByte != nil {
panic(errByte)
}
hashByte1 := append(AByte, BByte...)
hashByte1 = append(hashByte1, aBaAByte...)
s = sha3.NewShake128()
_, errWrite = s.Write(hashByte1)
if errWrite != nil {
panic(errWrite)
}
_, errRead = s.Read(sender.k1)
if errRead != nil {
panic(errRead)
}

e0 := aesEncGCM(sender.k0, sender.m0)
sender.e0 = e0

e1 := aesEncGCM(sender.k1, sender.m1)
sender.e1 = e1

return sender.e0, sender.e1
}

// Round 3

// ---- sender should send e0, e1 to receiver ----

// Input: e0, e1: encryption of m0 and m1 from the sender
// Input: choice, choice bit of receiver
// Choose e0 or e1 based on choice bit in constant time
func (receiver *ReceiverSimOT) Round3Receiver(e0, e1 []byte, choice int) error {
receiver.ec = make([]byte, len(e1))
// If c == 1, copy e1
subtle.ConstantTimeCopy(choice, receiver.ec, e1)
// If c == 0, copy e0
subtle.ConstantTimeCopy(1-choice, receiver.ec, e0)

AByte, errByte := receiver.A.MarshalBinary()
if errByte != nil {
panic(errByte)
}
BByte, errByte := receiver.B.MarshalBinary()
if errByte != nil {
panic(errByte)
}
bA := receiver.myGroup.NewElement()
bA.Mul(receiver.A, receiver.b)
bAByte, errByte := bA.MarshalBinary()
if errByte != nil {
panic(errByte)
}
// Hash the whole transcript so far
hashByte := append(AByte, BByte...)
hashByte = append(hashByte, bAByte...)

s := sha3.NewShake128()
_, errWrite := s.Write(hashByte)
if errWrite != nil {
panic(errWrite)
}
_, errRead := s.Read(receiver.kR) // kR, decryption key of mc
if errRead != nil {
panic(errRead)
}
mc, errDec := aesDecGCM(receiver.kR, receiver.ec)
if errDec != nil {
return errDec
}
receiver.mc = mc
return nil
}

func (receiver *ReceiverSimOT) Returnmc() []byte {
return receiver.mc
}

func (sender *SenderSimOT) Returne0e1() ([]byte, []byte) {
return sender.e0, sender.e1
}

func (sender *SenderSimOT) Returnm0m1() ([]byte, []byte) {
return sender.m0, sender.m1
}
29 changes: 29 additions & 0 deletions ot/simplestOT/simplestOTParty.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package simplestOT

import "github.com/cloudflare/circl/group"

type SenderSimOT struct {
index int // Indicate which OT
m0 []byte // The M0 message from sender
m1 []byte // The M1 message from sender
a group.Scalar // The randomness of the sender
A group.Element // [a]G
B group.Element // The random group element from the receiver
k0 []byte // The encryption key of M0
k1 []byte // The encryption key of M1
e0 []byte // The encryption of M0 under k0
e1 []byte // The encryption of M1 under k1
myGroup group.Group // The elliptic curve we operate in
}

type ReceiverSimOT struct {
index int // Indicate which OT
c int // The choice bit of the receiver
A group.Element // The random group element from the sender
b group.Scalar // The randomness of the receiver
B group.Element // B = [b]G if c == 0, B = A+[b]G if c == 1
kR []byte // The decryption key of receiver
ec []byte // The encryption of mc
mc []byte // The decrypted message from sender
myGroup group.Group // The elliptic curve we operate in
}