mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-12-29 18:05:18 +00:00
152 lines
4.2 KiB
Go
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,
|
||
|
}
|
||
|
}
|