3.2 Public vs Private
In this chapter we'll go through the core concepts that separate Leo from languages used on other blockchains.
Remember, Leo is a language that was made to write programs, where users are able prove that some function returns some outputs on given inputs. The prover always knows what those inputs and outputs are. On the contrary, when writing the program you can chose what inputs and outputs the verifier will be able to know.
To specify which inputs/outputs will be visible by the verifier, you use the private or public keywords.
Here's a first example. Let's say a user wants to prove he knows a values which has a specific hash. He could use a program with the following code:
program public_private.aleo {
transition hash(private a: u128) -> (public u128) {
let hashed: u128 = BHP256::hash_to_u128(a);
// 'BHP256::hash_to_u128' is simply some hash function
return hashed;
}
}
And then execute the following command to generate the proof on input 123u128
:
leo execute hash 123u128
The execution JSON output gives (truncated, for clarity):
...
"program": "public_private.aleo",
"function": "hash",
"inputs": [
{
"type": "private",
"id": "1962240563724633819199836007983492948966298136554977151826721901937221388753field",
"value": "ciphertext1qyq2524n4k73nz6ws6qf3xn6d9ud2a02aja4x0qmp85jnk57cxvq6rs2mqut3"
}
],
"outputs": [
{
"type": "public",
"id": "6397735181602383364235662871012389317153917860343012180688468769946408542910field",
"value": "26515625101883903322553063858644017311u128"
}
],
...
As you can see here the type of the only input is private, and the value is a ciphertext, which can be decrypted using the prover view key to recover the input value itelf. On the contrary the output is a public value: 26515625101883903322553063858644017311u128
which corresponds directly to the hash of 123u128
.
Transitions can have up to 16 inputs and outputs, which can all independently be tagged as public or private.
The address of the prover itself is private as well, and accessible in a program using the self.signer
keyword. For example the following code could be used to prove that the prover's address is one of the three hardcoded addresses:
program public_private.aleo {
transition includes_signer() -> (public bool) {
let included: bool = (
self.signer == aleo1845psejz2fqy3zwjvdxjrexs9fwdh2tqjwlhtdjs2t6thr07ccyq3fvmfd
|| self.signer == aleo1hqrz7wukfv2mmxzuzwes0w44s2se2v98w840k6euncdm8mwfd5pq2dwjcy
|| self.signer == aleo15eapl52ju8a6zxz5qnau7nlvadz3x3napa0qds7c04d8qkt6f5gs747czs
);
return included;
}
}
The execution of this function, along with its proof, reveals nothing about the prover address other than if it's included or not in the list of three addresses.
We're still missing a last important piece of input/output visibility that's available on Aleo. But before looking into it, we need to describe first all the types available in the language.
Last updated