Skip to content

Commit ecb99b9

Browse files
authored
Merge branch 'main' into Soumya8898/self-adjusting-histogram-buckets
2 parents 60d635d + b5aaea3 commit ecb99b9

2 files changed

Lines changed: 282 additions & 58 deletions

File tree

token/core/zkatdlog/nogh/v1/crypto/rp/csp/rp.go

Lines changed: 92 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
"math/big"
1111

1212
mathlib "github.com/IBM/mathlib"
13+
bls12381fr "github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
14+
bn254fr "github.com/consensys/gnark-crypto/ecc/bn254/fr"
1315
"github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors"
1416
"github.com/hyperledger-labs/fabric-token-sdk/token/core/common/encoding/asn1"
1517
"github.com/hyperledger-labs/fabric-token-sdk/token/core/zkatdlog/nogh/v1/crypto/math"
@@ -276,14 +278,32 @@ func (rp *rangeProver) Prove() (*RangeProof, error) {
276278
if err != nil {
277279
return nil, errors.New("Unable to obtain partial lagrange multipliers")
278280
}
279-
u := math.InnerProduct(aCoeffs, mu, rp.Curve)
281+
// Compute u = <aCoeffs, mu> — dispatch to native for supported curves.
282+
isBLS, isBN254 := math.DispatchCurve(rp.Curve)
283+
var u *mathlib.Zr
284+
if isBLS {
285+
u = nativeRPInnerProduct[bls12381fr.Element, *bls12381fr.Element](aCoeffs, mu, rp.Curve)
286+
} else if isBN254 {
287+
u = nativeRPInnerProduct[bn254fr.Element, *bn254fr.Element](aCoeffs, mu, rp.Curve)
288+
} else {
289+
u = math.InnerProduct(aCoeffs, mu, rp.Curve)
290+
}
280291

281292
tr.Absorb(u.Bytes())
282293
gamma, err := tr.Squeeze()
283294
if err != nil {
284295
return nil, errors.New("Unable to obtain challenge gamma")
285296
}
286297

298+
// Compute paddedSize for lf/wit (next power of 2 >= 2n+4).
299+
witSize := 2*n + 4
300+
cspRounds := uint64(0)
301+
paddedSize := uint64(1)
302+
for paddedSize < witSize {
303+
paddedSize <<= 1
304+
cspRounds++
305+
}
306+
287307
// Extended commitment: pCommExt = pComm + eta * VCommitment.
288308
pCommExt := pComm.Copy()
289309
pCommExt.Add(rp.VCommitment.Mul(eta))
@@ -299,53 +319,66 @@ func (rp *rangeProver) Prove() (*RangeProof, error) {
299319
gExt[2*n+2] = rp.VGenerators[0].Mul(eta)
300320
gExt[2*n+3] = rp.VGenerators[1].Mul(eta)
301321

302-
// Build aggregated linear form lf = L1 + gamma*L2 + gamma^2*L3 over pExt.
303-
//
304-
// pExt layout [0..n]=aCoeffs [n+1..2n+1]=bCoeffs [2n+2]=v [2n+3]=r
305-
//
306-
// L1: eta*2^{i-1} at [1..n], -eta at [2n+2] → checks eta*(Σ a_i·2^{i-1} - v) = 0
307-
// L2: mu[i] at [0..n] → checks a(c) = u
308-
// L3: nu[k] at [n+1..2n+1] (k=0..n) → checks b(c) = u*(u-1)
309-
gammaSquare := rp.Curve.ModMul(gamma, gamma, rp.Curve.GroupOrder)
310-
lf := make([]*mathlib.Zr, len(pExt))
311-
for i := range lf {
312-
lf[i] = math.Zero(rp.Curve)
313-
}
314-
// L1 contribution1s.
315-
for i := uint64(1); i <= n; i++ {
316-
lf[i] = rp.Curve.ModMul(eta, math.PowerOfTwo(rp.Curve, i-1), rp.Curve.GroupOrder)
317-
}
318-
negEta := eta.Copy()
319-
negEta.Neg()
320-
lf[2*n+2] = negEta
321-
// L2 contributions: add gamma*mu[i] at positions 0..n.
322-
for i := uint64(0); i <= n; i++ {
323-
lf[i] = rp.Curve.ModAddMul2(
324-
lf[i], math.One(rp.Curve),
325-
gamma, mu[i],
322+
// Build aggregated linear form, and compute lVal.
323+
// Dispatch to native gnark arithmetic for supported curves.
324+
var lf []*mathlib.Zr
325+
var lVal *mathlib.Zr
326+
if isBLS {
327+
lf, _, lVal = nativeRPBuildLF[bls12381fr.Element, *bls12381fr.Element](
328+
n, eta, gamma, mu, nu, aCoeffs, u, rp.Curve)
329+
} else if isBN254 {
330+
lf, _, lVal = nativeRPBuildLF[bn254fr.Element, *bn254fr.Element](
331+
n, eta, gamma, mu, nu, aCoeffs, u, rp.Curve)
332+
} else {
333+
gammaSquare := rp.Curve.ModMul(gamma, gamma, rp.Curve.GroupOrder)
334+
lf = make([]*mathlib.Zr, len(pExt))
335+
for i := range lf {
336+
lf[i] = math.Zero(rp.Curve)
337+
}
338+
// L1 contribution1s.
339+
for i := uint64(1); i <= n; i++ {
340+
lf[i] = rp.Curve.ModMul(eta, math.PowerOfTwo(rp.Curve, i-1), rp.Curve.GroupOrder)
341+
}
342+
negEta := eta.Copy()
343+
negEta.Neg()
344+
lf[2*n+2] = negEta
345+
// L2 contributions: add gamma*mu[i] at positions 0..n.
346+
for i := uint64(0); i <= n; i++ {
347+
lf[i] = rp.Curve.ModAddMul2(
348+
lf[i], math.One(rp.Curve),
349+
gamma, mu[i],
350+
rp.Curve.GroupOrder,
351+
)
352+
}
353+
// L3 contributions: gamma^2*nu[k] at positions n+1..2n+1.
354+
for k := uint64(0); k <= n; k++ {
355+
lf[n+1+k] = rp.Curve.ModMul(gammaSquare, nu[k], rp.Curve.GroupOrder)
356+
}
357+
358+
// Claimed value: lVal = gamma*u + gamma^2*u*(u-1) (L1(pExt)=0 for honest prover).
359+
uMinus1 := rp.Curve.ModSub(u, math.One(rp.Curve), rp.Curve.GroupOrder)
360+
lVal = rp.Curve.ModAddMul2(
361+
gamma, u,
362+
gammaSquare, rp.Curve.ModMul(u, uMinus1, rp.Curve.GroupOrder),
326363
rp.Curve.GroupOrder,
327364
)
328365
}
329-
// L3 contributions: gamma^2*nu[k] at positions n+1..2n+1.
330-
for k := uint64(0); k <= n; k++ {
331-
lf[n+1+k] = rp.Curve.ModMul(gammaSquare, nu[k], rp.Curve.GroupOrder)
332-
}
333-
334-
// Claimed value: lVal = gamma*u + gamma^2*u*(u-1) (L1(pExt)=0 for honest prover).
335-
uMinus1 := rp.Curve.ModSub(u, math.One(rp.Curve), rp.Curve.GroupOrder)
336-
lVal := rp.Curve.ModAddMul2(
337-
gamma, u,
338-
gammaSquare, rp.Curve.ModMul(u, uMinus1, rp.Curve.GroupOrder),
339-
rp.Curve.GroupOrder,
340-
)
341366

342367
// ZK blinding: random sBlind, commit it, evaluate L on it.
343368
sBlind := make([]*mathlib.Zr, len(pExt))
344369
for i := range sBlind {
345370
sBlind[i] = rp.Curve.NewRandomZr(rand)
346371
}
347372
sComm := rp.Curve.MultiScalarMul(gExt, sBlind)
348-
sVal := math.InnerProduct(lf, sBlind, rp.Curve)
373+
// Compute sVal = ⟨lf, sBlind⟩ — dispatch to native for supported curves.
374+
var sVal *mathlib.Zr
375+
if isBLS {
376+
sVal = nativeRPInnerProduct[bls12381fr.Element, *bls12381fr.Element](lf, sBlind, rp.Curve)
377+
} else if isBN254 {
378+
sVal = nativeRPInnerProduct[bn254fr.Element, *bn254fr.Element](lf, sBlind, rp.Curve)
379+
} else {
380+
sVal = math.InnerProduct(lf, sBlind, rp.Curve)
381+
}
349382
tr.Absorb(sComm.Bytes())
350383
tr.Absorb(sVal.Bytes())
351384

@@ -354,33 +387,34 @@ func (rp *rangeProver) Prove() (*RangeProof, error) {
354387
return nil, errors.New("Unable to obtain challenge rho")
355388
}
356389

357-
// Blinded witness: wit = pExt + rho*sBlind so that
358-
// MSM(gExt, wit) = pCommExt + rho*sComm
359-
// L(wit) = lVal + rho*sVal
360-
wit := make([]*mathlib.Zr, len(pExt))
361-
for i := range pExt {
362-
wit[i] = rp.Curve.ModAddMul2(
363-
pExt[i], math.One(rp.Curve),
364-
rho, sBlind[i],
390+
// Compute wit and witVal — dispatch to native for supported curves.
391+
var wit []*mathlib.Zr
392+
var witVal *mathlib.Zr
393+
if isBLS {
394+
wit, witVal = nativeRPBlindWitness[bls12381fr.Element, *bls12381fr.Element](
395+
sBlind, pExt, rho, lVal, sVal, rp.Curve)
396+
} else if isBN254 {
397+
wit, witVal = nativeRPBlindWitness[bn254fr.Element, *bn254fr.Element](
398+
sBlind, pExt, rho, lVal, sVal, rp.Curve)
399+
} else {
400+
wit = make([]*mathlib.Zr, len(pExt))
401+
for i := range pExt {
402+
wit[i] = rp.Curve.ModAddMul2(
403+
pExt[i], math.One(rp.Curve),
404+
rho, sBlind[i],
405+
rp.Curve.GroupOrder,
406+
)
407+
}
408+
witVal = rp.Curve.ModAddMul2(
409+
lVal, math.One(rp.Curve),
410+
rho, sVal,
365411
rp.Curve.GroupOrder,
366412
)
367413
}
368414
witComm := pCommExt.Copy()
369415
witComm.Add(sComm.Mul(rho))
370-
witVal := rp.Curve.ModAddMul2(
371-
lVal, math.One(rp.Curve),
372-
rho, sVal,
373-
rp.Curve.GroupOrder,
374-
)
375416

376417
// Pad witness / generators / linear form to the next power of 2 for CSP.
377-
witSize := uint64(len(wit))
378-
cspRounds := uint64(0)
379-
paddedSize := uint64(1)
380-
for paddedSize < witSize {
381-
paddedSize <<= 1
382-
cspRounds++
383-
}
384418
for uint64(len(wit)) < paddedSize {
385419
wit = append(wit, math.Zero(rp.Curve))
386420
gExt = append(gExt, rp.Curve.GenG1)
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package csp
8+
9+
import (
10+
mathlib "github.com/IBM/mathlib"
11+
math2 "github.com/hyperledger-labs/fabric-token-sdk/token/core/zkatdlog/nogh/v1/crypto/math"
12+
)
13+
14+
// nativeRPBuildLF constructs the aggregated linear form lf = L1 + gamma·L2 + gamma²·L3,
15+
// computes u (either from aCoeffs for the prover or directly from proofU for the verifier),
16+
// and evaluates lVal = gamma·u + gamma²·u·(u-1).
17+
//
18+
// All O(n) scalar multiplications and additions run in native gnark Montgomery form,
19+
// avoiding big.Int round-trips through mathlib.Zr.
20+
//
21+
// Parameters:
22+
// - n: number of bits (NumberOfBits)
23+
// - eta, gamma: Fiat-Shamir challenges
24+
// - mu: Lagrange multipliers over {0,...,n} (length n+1)
25+
// - nu: partial Lagrange multipliers over {0, n+1,...,2n} (length n+1)
26+
// - aCoeffs: polynomial coefficients (length n+1), non-nil for prover
27+
// - proofU: evaluator's claimed u value, non-nil for verifier
28+
// - paddedSize: total size of the extended generator/lf vector (≥ 2n+4)
29+
// - curve: the mathematical curve
30+
//
31+
// Returns:
32+
// - lf: the aggregated linear form vector of length paddedSize (padded with zeros)
33+
// - u: prover evaluation a(c) or verifier's proof.u
34+
// - lVal: gamma·u + gamma²·u·(u-1)
35+
func nativeRPBuildLF[T any, E math2.GnarkFr[T]](
36+
n uint64,
37+
eta, gamma *mathlib.Zr,
38+
mu, nu []*mathlib.Zr,
39+
aCoeffs []*mathlib.Zr, // non-nil for prover
40+
proofU *mathlib.Zr, // non-nil for verifier
41+
curve *mathlib.Curve,
42+
) ([]*mathlib.Zr, *mathlib.Zr, *mathlib.Zr) {
43+
// Convert challenges to native form once.
44+
etaE := math2.NativeFromZr[T, E](eta)
45+
gammaE := math2.NativeFromZr[T, E](gamma)
46+
var gammaSqE T
47+
E(&gammaSqE).Mul(gammaE, gammaE)
48+
49+
// Convert mu and nu to native form.
50+
muE := make([]T, n+1)
51+
for i := uint64(0); i <= n; i++ {
52+
math2.SetNativeFromZr[T, E](mu[i], E(&muE[i]))
53+
}
54+
nuE := make([]T, n+1)
55+
for i := uint64(0); i <= n; i++ {
56+
math2.SetNativeFromZr[T, E](nu[i], E(&nuE[i]))
57+
}
58+
59+
// Build lf in native form (size 2n+4, then pad to paddedSize).
60+
lfSize := 2*n + 4
61+
lfE := make([]T, lfSize)
62+
63+
// lf[0] = zero initially (will be updated by L2)
64+
// lf[i] for i=1..n: L1 contribution = eta * 2^{i-1}
65+
var twoE T
66+
E(&twoE).SetInt64(2)
67+
var powE T
68+
E(&powE).SetOne() // 2^0 = 1
69+
70+
for i := uint64(1); i <= n; i++ {
71+
E(&lfE[i]).Mul(etaE, E(&powE))
72+
E(&powE).Mul(E(&powE), E(&twoE))
73+
}
74+
75+
// lf[2n+2] = -eta
76+
var negEtaE T
77+
E(&negEtaE).SetZero()
78+
E(&negEtaE).Sub(E(&negEtaE), etaE)
79+
lfE[2*n+2] = negEtaE
80+
81+
// L2 contributions: lf[i] += gamma * mu[i] for i=0..n
82+
var tmpE T
83+
for i := uint64(0); i <= n; i++ {
84+
E(&tmpE).Mul(gammaE, E(&muE[i]))
85+
E(&lfE[i]).Add(E(&lfE[i]), E(&tmpE))
86+
}
87+
88+
// L3 contributions: lf[n+1+k] = gamma^2 * nu[k] for k=0..n
89+
for k := uint64(0); k <= n; k++ {
90+
E(&lfE[n+1+k]).Mul(E(&gammaSqE), E(&nuE[k]))
91+
}
92+
93+
// Convert lf to mathlib.Zr.
94+
lf := make([]*mathlib.Zr, lfSize)
95+
for i := range lfSize {
96+
lf[i] = math2.NativeToZr[T, E](E(&lfE[i]), curve)
97+
}
98+
99+
// Compute u: either from aCoeffs (prover) or proofU (verifier).
100+
var uE T
101+
if aCoeffs != nil {
102+
// u = <aCoeffs, mu> via native inner product
103+
E(&uE).SetZero()
104+
for i := uint64(0); i <= n; i++ {
105+
var aE T
106+
math2.SetNativeFromZr[T, E](aCoeffs[i], E(&aE))
107+
E(&tmpE).Mul(E(&aE), E(&muE[i]))
108+
E(&uE).Add(E(&uE), E(&tmpE))
109+
}
110+
} else {
111+
math2.SetNativeFromZr[T, E](proofU, E(&uE))
112+
}
113+
u := math2.NativeToZr[T, E](E(&uE), curve)
114+
115+
// lVal = gamma * u + gamma^2 * u * (u - 1)
116+
var oneE T
117+
E(&oneE).SetOne()
118+
var uMinus1E T
119+
E(&uMinus1E).Sub(E(&uE), E(&oneE))
120+
121+
var lValE T
122+
E(&lValE).Mul(gammaE, E(&uE)) // gamma * u
123+
E(&tmpE).Mul(E(&uE), E(&uMinus1E)) // u * (u-1)
124+
E(&tmpE).Mul(E(&gammaSqE), E(&tmpE)) // gamma^2 * u * (u-1)
125+
E(&lValE).Add(E(&lValE), E(&tmpE)) // gamma*u + gamma^2*u*(u-1)
126+
lVal := math2.NativeToZr[T, E](E(&lValE), curve)
127+
128+
return lf, u, lVal
129+
}
130+
131+
// nativeRPInnerProduct computes the inner product ⟨lf, sBlind⟩ using native gnark
132+
// arithmetic. Called before rho is available.
133+
func nativeRPInnerProduct[T any, E math2.GnarkFr[T]](
134+
lf, sBlind []*mathlib.Zr,
135+
curve *mathlib.Curve,
136+
) *mathlib.Zr {
137+
m := len(lf)
138+
139+
var sValE T
140+
E(&sValE).SetZero()
141+
var tmpE, lfI, sbI T
142+
for i := range m {
143+
math2.SetNativeFromZr[T, E](lf[i], E(&lfI))
144+
math2.SetNativeFromZr[T, E](sBlind[i], E(&sbI))
145+
E(&tmpE).Mul(E(&lfI), E(&sbI))
146+
E(&sValE).Add(E(&sValE), E(&tmpE))
147+
}
148+
149+
return math2.NativeToZr[T, E](E(&sValE), curve)
150+
}
151+
152+
// nativeRPBlindWitness computes the blinded witness and evaluation after rho is known:
153+
// - wit[i] = pExt[i] + rho · sBlind[i] (nil if sBlind is nil, e.g. for verifier)
154+
// - witVal = lVal + rho · sVal
155+
//
156+
// All scalar arithmetic runs in native gnark Montgomery form.
157+
// When called from the verifier, sBlind and pExt may be nil; in that case only
158+
// witVal is computed and wit is returned as nil.
159+
func nativeRPBlindWitness[T any, E math2.GnarkFr[T]](
160+
sBlind, pExt []*mathlib.Zr,
161+
rho, lVal, sVal *mathlib.Zr,
162+
curve *mathlib.Curve,
163+
) ([]*mathlib.Zr, *mathlib.Zr) {
164+
rhoE := math2.NativeFromZr[T, E](rho)
165+
166+
// wit[i] = pExt[i] + rho * sBlind[i] — skipped when called from verifier.
167+
var wit []*mathlib.Zr
168+
if sBlind != nil && pExt != nil {
169+
m := len(pExt)
170+
wit = make([]*mathlib.Zr, m)
171+
var tmpE, sbI, pI T
172+
for i := range m {
173+
math2.SetNativeFromZr[T, E](sBlind[i], E(&sbI))
174+
math2.SetNativeFromZr[T, E](pExt[i], E(&pI))
175+
E(&tmpE).Mul(rhoE, E(&sbI))
176+
E(&tmpE).Add(E(&pI), E(&tmpE))
177+
wit[i] = math2.NativeToZr[T, E](E(&tmpE), curve)
178+
}
179+
}
180+
181+
// witVal = lVal + rho * sVal
182+
lValE := math2.NativeFromZr[T, E](lVal)
183+
sValE := math2.NativeFromZr[T, E](sVal)
184+
var witValE T
185+
E(&witValE).Mul(rhoE, sValE)
186+
E(&witValE).Add(lValE, E(&witValE))
187+
witVal := math2.NativeToZr[T, E](E(&witValE), curve)
188+
189+
return wit, witVal
190+
}

0 commit comments

Comments
 (0)