ceremonyclient/nekryptology/test/verenc/share_proof/main.go
2023-07-05 00:32:28 -05:00

152 lines
4.2 KiB
Go

package main
import (
crand "crypto/rand"
"fmt"
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/sharing"
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/verenc/elgamal"
)
func main() {
// Setup
curve := curves.ED25519()
serverPk, serverSk, _ := elgamal.NewKeys(curve)
aliceEk, _, _ := elgamal.NewKeys(curve)
bobEk, _, _ := elgamal.NewKeys(curve)
signKey := curve.Scalar.Random(crand.Reader)
verKey := curve.ScalarBaseMult(signKey)
shamir, _ := sharing.NewShamir(2, 2, curve)
shares, _ := shamir.Split(signKey, crand.Reader)
// Create a proof s.t. Alice and Bob submit
// proofs of correctness for their ciphertexts
// Alice and Bob can decrypt their respective shares
// But the server cannot.
// The server checks whether the ciphertexts
// are valid encrypted shares
aliceDomain := []byte("alice_share")
bobDomain := []byte("bob_share")
aliceStuff := computeProof(curve, shares[0].Value, aliceDomain, aliceEk, serverPk)
bobStuff := computeProof(curve, shares[1].Value, bobDomain, bobEk, serverPk)
if !verifyProof(curve, aliceStuff, aliceDomain, aliceEk, serverPk) {
panic("bad alice proof")
}
if !verifyProof(curve, bobStuff, bobDomain, bobEk, serverPk) {
panic("bad bob proof")
}
aliceShare, _ := aliceStuff.serverctxt.ToHomomorphicCipherText().Decrypt(serverSk)
bobShare, _ := bobStuff.serverctxt.ToHomomorphicCipherText().Decrypt(serverSk)
avk := shamirCombinePoint(curve, []curves.Point{aliceShare, bobShare})
if avk.Equal(verKey) {
fmt.Println("Success")
} else {
fmt.Println("Failure")
}
}
func shamirCombinePoint(curve *curves.Curve, points []curves.Point) curves.Point {
result := curve.Point.Identity()
for i, p := range points {
basis := curve.Scalar.One()
for j := range points {
if i == j {
continue
}
// x_m - x_j
denom := curve.Scalar.New(j + 1).Sub(curve.Scalar.New(i + 1))
if denom.IsZero() {
return nil
}
// x_m / x_m - x_j
basis = basis.Mul(curve.Scalar.New(j + 1).Div(denom))
}
result = result.Add(p.Mul(basis))
}
return result
}
func verifyProof(
curve *curves.Curve,
proof *commitTwinProof,
domain []byte,
encKey *elgamal.EncryptionKey,
serverPk *elgamal.EncryptionKey,
) bool {
genBytes := append(domain, encKey.Value.ToAffineUncompressed()...)
genBytes = append(genBytes, proof.encctxt.Nonce...)
h := curve.NewGeneratorPoint().Hash(genBytes)
w1 := curve.ScalarBaseMult(proof.d).Add(serverPk.Value.Mul(proof.d1)).Add(proof.serverctxt.C2.Mul(proof.c))
w2 := h.Mul(proof.d).Add(encKey.Value.Mul(proof.d2)).Add(proof.encctxt.C2.Mul(proof.c))
c := curve.NewScalar().Hash(append(w1.ToAffineCompressed(), w2.ToAffineCompressed()...))
return c.Cmp(proof.c) == 0
}
type commitTwinProof struct {
c, d, d1, d2 curves.Scalar
serverctxt *elgamal.CipherText
encctxt *elgamal.CipherText
}
func computeProof(
curve *curves.Curve,
share, domain []byte,
encKey *elgamal.EncryptionKey,
servKey *elgamal.EncryptionKey,
) *commitTwinProof {
r1 := curve.Scalar.Random(crand.Reader)
r2 := curve.Scalar.Random(crand.Reader)
encctxt, _, _ := encKey.VerifiableEncrypt(share, &elgamal.EncryptParams{
Domain: domain,
Blinding: r2,
MessageIsHashed: true,
ProofNonce: domain,
})
serverCtxt, _, _ := servKey.VerifiableEncrypt(share, &elgamal.EncryptParams{
Blinding: r1,
MessageIsHashed: true,
ProofNonce: domain,
})
w := curve.Scalar.Random(crand.Reader)
n1 := curve.Scalar.Random(crand.Reader)
n2 := curve.Scalar.Random(crand.Reader)
genBytes := append(domain, encKey.Value.ToAffineUncompressed()...)
genBytes = append(genBytes, encctxt.Nonce...)
h := curve.NewGeneratorPoint().Hash(genBytes)
w1 := curve.ScalarBaseMult(w).Add(servKey.Value.Mul(n1))
w2 := h.Mul(w).Add(encKey.Value.Mul(n2))
c := curve.NewScalar().Hash(append(w1.ToAffineCompressed(), w2.ToAffineCompressed()...))
s, err := curve.NewScalar().SetBytes(share)
if err != nil {
panic(err)
}
// d = w - c s
d := w.Sub(c.Mul(s))
// d1 = n1 - c r1
d1 := n1.Sub(c.Mul(r1))
// d2 = n2 - c r2
d2 := n2.Sub(c.Mul(r2))
return &commitTwinProof{
c: c,
d: d,
d1: d1,
d2: d2,
encctxt: encctxt,
serverctxt: serverCtxt,
}
}