rename folder and reworked the transaction

This commit is contained in:
thomaslavaur 2025-04-09 14:04:39 +02:00
parent 39fdbd972f
commit dab1ebd4bf
6 changed files with 130 additions and 102 deletions

View File

@ -205,89 +205,94 @@ def PoseidonSponge(data, capacity, output_len):
R = RealField(500) #Real numbers with precision 500 bits
if len(sys.argv) != Integer(3):
print("Usage: <script> <nInputs> <nOutputs> ")
print("Usage: <script> <maxInputs> <maxOutputs> ")
exit()
nInputs = int(sys.argv[Integer(1)])
nOutputs = int(sys.argv[Integer(2)])
maxInputs = int(sys.argv[Integer(1)])
maxOutputs = int(sys.argv[Integer(2)])
value_in = [F(randrange(0,10000,1) )for i in range(nInputs) ]
value_in = [F(randrange(0,10000,1) )for i in range(maxInputs) ]
unit = F(19676183153323264216568033390884511718872104179761154996527087027500271872825)
state_in = [F(randrange(0,p,1)) for i in range(nInputs) ]
zone_in = [F(randrange(0,p,1)) for i in range(nInputs) ]
note_nonce_in = [F(randrange(0,p,1)) for i in range(nInputs)]
sk_in = [F(randrange(0,p,1)) for i in range(nInputs)]
pk_in = [ poseidon2_hash([F(355994159511987982411097843485998670968942801951585260613801918349630142543),sk_in[i]]) for i in range(nInputs) ]
state_in = [F(randrange(0,p,1)) for i in range(maxInputs) ]
zone_in = [F(randrange(0,p,1)) for i in range(maxInputs) ]
note_nonce_in = [F(randrange(0,p,1)) for i in range(maxInputs)]
sk_in = [F(randrange(0,p,1)) for i in range(maxInputs)]
pk_in = [ poseidon2_hash([F(355994159511987982411097843485998670968942801951585260613801918349630142543),sk_in[i]]) for i in range(maxInputs) ]
attached_data = F(randrange(0,p,1))
note_cm_in = [poseidon2_hash([F(181645510297841241569044198526601622686169271532834574969543446901055041748),state_in[i],value_in[i],unit,note_nonce_in[i],pk_in[i],zone_in[i]]) for i in range(nInputs) ]
cm_nodes = [[F(randrange(0,p,1)) for i in range(32)] for j in range(nInputs) ]
cm_selectors = [format(randrange(0,2**32,1),'032b') for i in range(nInputs) ]
cm_root = [ note_cm_in[i] for i in range(nInputs) ]
for j in range(nInputs):
note_cm_in = [poseidon2_hash([F(181645510297841241569044198526601622686169271532834574969543446901055041748),state_in[i],value_in[i],unit,note_nonce_in[i],pk_in[i],zone_in[i]]) for i in range(maxInputs) ]
cm_nodes = [[F(randrange(0,p,1)) for i in range(32)] for j in range(maxInputs) ]
cm_selectors = [format(randrange(0,2**32,1),'032b') for i in range(maxInputs) ]
cm_root = [ note_cm_in[i] for i in range(maxInputs) ]
for j in range(maxInputs):
for i in range(32):
if int(cm_selectors[j][31-i]) == 0:
cm_root[j] = poseidon2_hash([cm_root[j],cm_nodes[j][i]])
else:
cm_root[j] = poseidon2_hash([cm_nodes[j][i],cm_root[j]])
value_out = [F(randrange(0,10000,1) )for i in range(nOutputs) ]
state_out = [F(randrange(0,p,1)) for i in range(nOutputs) ]
note_nonce_out = [F(randrange(0,p,1)) for i in range(nOutputs)]
pk_out = [ F(randrange(0,p,1)) for i in range(nOutputs)]
zone_out = [F(randrange(0,p,1)) for i in range(nOutputs) ]
value_out = [F(randrange(0,10000,1) )for i in range(maxOutputs) ]
state_out = [F(randrange(0,p,1)) for i in range(maxOutputs) ]
note_nonce_out = [F(randrange(0,p,1)) for i in range(maxOutputs)]
pk_out = [ F(randrange(0,p,1)) for i in range(maxOutputs)]
zone_out = [F(randrange(0,p,1)) for i in range(maxOutputs)]
is_a_input_note = [F(randrange(0,1,1)) for i in range(maxInputs)]
is_a_output_note = [F(randrange(0,1,1)) for i in range(maxOutputs)]
is_a_input_note[0] = F(1)
is_a_output_note[0] = F(1)
with open("input.json", "w") as file:
file.write('{\n\t"minting_covenant" :\t\t\t\t"'+str(0)+'",')
file.write('\n\t"burning_covenant" :\t\t\t\t"'+str(0)+'",')
file.write('\n\t"state_in" :\t\t\t\t\t[')
for i in range(nInputs):
for i in range(maxInputs):
file.write('"')
file.write(str(state_in[i]))
file.write('"')
if i == (nInputs-1):
if i == (maxInputs-1):
file.write('],')
else:
file.write(',')
file.write('\n\t"value_in" :\t\t\t\t\t[')
for i in range(nInputs):
for i in range(maxInputs):
file.write('"')
file.write(str(value_in[i]))
file.write('"')
if i == (nInputs-1):
if i == (maxInputs-1):
file.write('],')
else:
file.write(',')
file.write('\n\t"nonce_in" :\t\t\t\t\t[')
for i in range(nInputs):
for i in range(maxInputs):
file.write('"')
file.write(str(note_nonce_in[i]))
file.write('"')
if i == (nInputs-1):
if i == (maxInputs-1):
file.write('],')
else:
file.write(',')
file.write('\n\t"secret_key_in" :\t\t\t\t\t[')
for i in range(nInputs):
for i in range(maxInputs):
file.write('"')
file.write(str(sk_in[i]))
file.write('"')
if i == (nInputs-1):
if i == (maxInputs-1):
file.write('],')
else:
file.write(',')
file.write('\n\t"zoneID_in" :\t\t\t\t\t[')
for i in range(nInputs):
for i in range(maxInputs):
file.write('"')
file.write(str(zone_in[i]))
file.write('"')
if i == (nInputs-1):
if i == (maxInputs-1):
file.write('],')
else:
file.write(',')
file.write('\n\t"cm_nodes" :\t\t\t\t\t[')
for i in range(nInputs):
for i in range(maxInputs):
file.write('\n\t\t\t\t\t\t[')
for j in range(32):
file.write('"')
@ -297,12 +302,12 @@ with open("input.json", "w") as file:
file.write(']')
else:
file.write(',')
if i == (nInputs-1):
if i == (maxInputs-1):
file.write('],')
else:
file.write(',')
file.write('\n\t"cm_selectors" :\t\t\t\t\t[')
for i in range(nInputs):
for i in range(maxInputs):
file.write('\n\t\t\t\t\t\t[')
for j in range(32):
file.write('"')
@ -312,62 +317,80 @@ with open("input.json", "w") as file:
file.write(']')
else:
file.write(',')
if i == (nInputs-1):
if i == (maxInputs-1):
file.write('],')
else:
file.write(',')
file.write('\n\t"commitments_root" :\t\t\t\t\t[')
for i in range(nInputs):
for i in range(maxInputs):
file.write('"')
file.write(str(cm_root[i]))
file.write('"')
if i == (nInputs-1):
if i == (maxInputs-1):
file.write('],')
else:
file.write(',')
file.write('\n\t"is_a_input_note" :\t\t\t\t\t[')
for i in range(maxInputs):
file.write('"')
file.write(str(is_a_input_note[i]))
file.write('"')
if i == (maxInputs-1):
file.write('],')
else:
file.write(',')
file.write('\n\t"attached_data" :\t\t\t\t\t\t"'+str(attached_data)+'",')
file.write('\n\t"state_out" :\t\t\t\t\t[')
for i in range(nOutputs):
for i in range(maxOutputs):
file.write('"')
file.write(str(state_out[i]))
file.write('"')
if i == (nOutputs-1):
if i == (maxOutputs-1):
file.write('],')
else:
file.write(',')
file.write('\n\t"value_out" :\t\t\t\t\t[')
for i in range(nOutputs):
for i in range(maxOutputs):
file.write('"')
file.write(str(value_out[i]))
file.write('"')
if i == (nOutputs-1):
if i == (maxOutputs-1):
file.write('],')
else:
file.write(',')
file.write('\n\t"nonce_out" :\t\t\t\t\t[')
for i in range(nOutputs):
for i in range(maxOutputs):
file.write('"')
file.write(str(note_nonce_out[i]))
file.write('"')
if i == (nOutputs-1):
if i == (maxOutputs-1):
file.write('],')
else:
file.write(',')
file.write('\n\t"public_key_out" :\t\t\t\t\t[')
for i in range(nOutputs):
for i in range(maxOutputs):
file.write('"')
file.write(str(pk_out[i]))
file.write('"')
if i == (nOutputs-1):
if i == (maxOutputs-1):
file.write('],')
else:
file.write(',')
file.write('\n\t"is_a_output_note" :\t\t\t\t\t[')
for i in range(maxOutputs):
file.write('"')
file.write(str(is_a_output_note[i]))
file.write('"')
if i == (maxOutputs-1):
file.write('],')
else:
file.write(',')
file.write('\n\t"zoneID_out" :\t\t\t\t\t[')
for i in range(nOutputs):
for i in range(maxOutputs):
file.write('"')
file.write(str(zone_out[i]))
file.write('"')
if i == (nOutputs-1):
if i == (maxOutputs-1):
file.write(']}')
else:
file.write(',')

View File

@ -4,36 +4,37 @@ pragma circom 2.1.9;
include "../ledger/notes.circom";
include "../misc/constants.circom";
template proof_of_private_note_ownership(nInput){
signal input state[nInput];
signal input value[nInput];
signal input nonce[nInput];
signal input zoneID[nInput];
signal input secret_key[nInput];
signal input minting_covenant[nInput];
signal input spending_covenant[nInput];
signal input burning_covenant[nInput];
template proof_of_private_note_ownership(maxInput){
signal input state[maxInput];
signal input value[maxInput];
signal input nonce[maxInput];
signal input zoneID[maxInput];
signal input secret_key[maxInput];
signal input minting_covenant[maxInput];
signal input spending_covenant[maxInput];
signal input burning_covenant[maxInput];
signal input is_an_input[maxInput];
signal input attached_data;
signal output commitment[nInput];
signal output commitment[maxInput];
component pk[nInput];
for(var i =0; i<nInput; i++){
component pk[maxInput];
for(var i =0; i<maxInput; i++){
pk[i] = derive_public_key();
pk[i].secret_key <== secret_key[i];
}
component unit[nInput];
for(var i=0; i< nInput; i++){
component unit[maxInput];
for(var i=0; i< maxInput; i++){
unit[i] = derive_unit();
unit[i].minting_covenant <== minting_covenant[i];
unit[i].spending_covenant <== spending_covenant[i];
unit[i].burning_covenant <== burning_covenant[i];
}
component cm[nInput];
for(var i =0; i< nInput; i++){
component cm[maxInput];
for(var i =0; i< maxInput; i++){
cm[i] = commitment();
cm[i].state <== state[i];
cm[i].value <== value[i];
@ -48,15 +49,15 @@ template proof_of_private_note_ownership(nInput){
dummy <== attached_data * attached_data;
}
template proof_of_public_note_ownership(nInput){
signal input secret_key[nInput];
template proof_of_public_note_ownership(maxInput){
signal input secret_key[maxInput];
signal input attached_data;
signal output public_key[nInput];
signal output public_key[maxInput];
component pk[nInput];
for(var i =0; i<nInput; i++){
component pk[maxInput];
for(var i =0; i<maxInput; i++){
pk[i] = derive_public_key();
pk[i].secret_key <== secret_key[i];
public_key[i] <== pk[i].out;

View File

@ -4,32 +4,35 @@ pragma circom 2.1.9;
include "../ledger/notes.circom";
include "../misc/constants.circom";
template transfer(nInputs, nOutputs){
template shielded_transaction(maxInputs, maxOutputs){
signal input minting_covenant; // Used to derive the unit and make sure the token use a no-op transfer covenant.
signal input minting_covenant; // Used to derive the unit and make sure the token use a no-op spending covenant.
signal input burning_covenant;
//consummed notes
// notes themselves
signal input state_in[nInputs];
signal input value_in[nInputs];
signal input nonce_in[nInputs];
signal input secret_key_in[nInputs];
signal input zoneID_in[nInputs];
signal input state_in[maxInputs];
signal input value_in[maxInputs];
signal input nonce_in[maxInputs];
signal input secret_key_in[maxInputs];
signal input zoneID_in[maxInputs];
// proof of commitment membership
signal input cm_nodes[nInputs][32];
signal input cm_selectors[nInputs][32]; // must be bits
signal input commitments_root[nInputs];
signal output nullifier[nInputs];
signal input cm_nodes[maxInputs][32];
signal input cm_selectors[maxInputs][32]; // must be bits
signal input commitments_root[maxInputs];
signal input is_a_input_note[maxInputs]; // Selector to say if note i is a real entry or a dummy input, must be 0 or 1
signal output nullifier[maxInputs]; // /!\ It needs to be checked outside the circuit by the validators
// Padding can be realized by repeating the same note on selector 0 (validators will ignore the nullifier)
//created notes
signal input state_out[nOutputs];
signal input value_out[nOutputs];
signal input nonce_out[nOutputs];
signal input public_key_out[nOutputs];
signal input zoneID_out[nOutputs];
signal output commitments[nOutputs];
signal input state_out[maxOutputs];
signal input value_out[maxOutputs];
signal input nonce_out[maxOutputs];
signal input public_key_out[maxOutputs];
signal input zoneID_out[maxOutputs];
signal input is_a_output_note[maxOutputs]; // Selector to say if note i is a real output or a dummy output, must be 0 or 1
signal output commitments[maxOutputs]; // /!\ It needs to be checked outside the circuit by the validators
// Padding can be realized by repeating the same note on selector 0 (validators will ignore the commitment)
signal input attached_data;
signal output balance;
@ -38,22 +41,22 @@ template transfer(nInputs, nOutputs){
//Derive the unit
component derive_unit = derive_unit();
derive_unit.minting_covenant <== minting_covenant;
derive_unit.transfer_covenant <== 0; // 0 encodes the fact that it's a no-op transfer covenant
derive_unit.spending_covenant <== 0; // 0 encodes the fact that it's a no-op transfer covenant
derive_unit.burning_covenant <== burning_covenant;
unit <== derive_unit.out;
// Verify the ownership of the consummed notes deriving the public keys from the secret keys
component pk[nInputs];
for(var i =0; i<nInputs; i++){
component pk[maxInputs];
for(var i =0; i<maxInputs; i++){
pk[i] = derive_public_key();
pk[i].secret_key <== secret_key_in[i];
}
// Derive the commitments of the consummed notes
component cm_in[nInputs];
for(var i =0; i<nInputs; i++){
component cm_in[maxInputs];
for(var i =0; i<maxInputs; i++){
cm_in[i] = commitment();
cm_in[i].state <== state_in[i];
cm_in[i].value <== value_in[i];
@ -64,8 +67,8 @@ template transfer(nInputs, nOutputs){
}
// Derive the nullifiers of the consummed notes
component nf[nInputs];
for(var i=0; i<nInputs; i++){
component nf[maxInputs];
for(var i=0; i<maxInputs; i++){
nf[i] = nullifier();
nf[i].commitment <== cm_in[i].out;
nf[i].secret_key <== secret_key_in[i];
@ -74,8 +77,8 @@ template transfer(nInputs, nOutputs){
// Prove the commitment membership against the chosen root(s)
component cm_membership[nInputs];
for(var i =0; i< nInputs; i++){
component cm_membership[maxInputs];
for(var i =0; i< maxInputs; i++){
//First check selectors are indeed bits
for(var j = 0; j < 32; j++){
cm_selectors[i][j] * (1 - cm_selectors[i][j]) === 0;
@ -92,8 +95,8 @@ template transfer(nInputs, nOutputs){
// Derive the commitments of the created notes
component cm_out[nOutputs];
for(var i =0; i<nOutputs; i++){
component cm_out[maxOutputs];
for(var i =0; i<maxOutputs; i++){
cm_out[i] = commitment();
cm_out[i].state <== state_out[i];
cm_out[i].value <== value_out[i];
@ -104,14 +107,15 @@ template transfer(nInputs, nOutputs){
commitments[i] <== cm_out[i].out;
}
var b = 0;
for(var i = 0; i< nInputs; i++){
b += value_in[i];
signal b[maxInputs + maxInputs];
b[0] <== value_in[0] * is_a_input_note[0];
for(var i = 1; i< maxInputs; i++){
b[i] <== b[i-1] + value_in[i] * is_a_input_note[i];
}
for(var i =0; i< nOutputs; i++){
b -= value_out[i];
for(var i =0; i< maxOutputs; i++){
b[i + maxInputs] <== b[maxInputs + i - 1] - value_out[i] * is_a_output_note[i];
}
balance <== b;
balance <== b[maxInputs + maxOutputs - 1];
//dummy quadratic contraints to avoid optimisation erasing the public input
signal dummy;
@ -119,4 +123,4 @@ template transfer(nInputs, nOutputs){
}
component main {public [zoneID_in,commitments_root,zoneID_out]}= transfer(4,4);
component main {public [zoneID_in,is_a_input_note,is_a_output_note,commitments_root,zoneID_out]}= shielded_transaction(4,4);