Module: Longfellow
- Defined in:
- lib/longfellow.rb,
lib/longfellow/c.rb,
lib/longfellow/errors.rb,
lib/longfellow/version.rb,
lib/longfellow/zk_spec.rb,
lib/longfellow/attribute.rb
Overview
Ruby bindings for Google’s longfellow-zk library (github.com/google/longfellow-zk): zero-knowledge proofs over ISO mdoc / mDL verifiable credentials.
The typical flow is:
spec = Longfellow.zk_specs.last # pick a ZK specification
circuit = Longfellow.generate_circuit(spec) # once; cache the result
proof = Longfellow.prove(circuit:, zk_spec:, ...) # prover side
Longfellow.verify(circuit:, zk_spec:, proof:, ...) # verifier side
Defined Under Namespace
Modules: C, Errors Classes: Attribute, CircuitGenerationError, Error, NativeError, ProverError, VerifierError, ZkSpec
Constant Summary collapse
- DEFAULT_DOC_TYPE =
Default mdoc document type (“org.iso.18013.5.1.mDL”).
"org.iso.18013.5.1.mDL"- VERSION =
"0.1.0"
Class Method Summary collapse
-
.circuit_id(circuit, zk_spec) ⇒ String
Compute the 32-byte identifier (SHA-256 over the two sub-circuit ids) of a compressed circuit bundle.
-
.find_zk_spec(system_name, circuit_hash) ⇒ Longfellow::ZkSpec?
Look up a ZK specification by system name and circuit hash.
-
.generate_circuit(zk_spec) ⇒ String
Produce the compressed circuit bytes for the given specification.
-
.prove(circuit:, mdoc:, public_key_x:, public_key_y:, transcript:, attributes:, now:, zk_spec:) ⇒ String
Generate a zero-knowledge proof opening the requested attributes of an mdoc.
-
.verify(circuit:, public_key_x:, public_key_y:, transcript:, attributes:, now:, proof:, zk_spec:, doc_type: DEFAULT_DOC_TYPE) ⇒ true
Verify a zero-knowledge proof against the requested attributes.
-
.zk_specs ⇒ Array<Longfellow::ZkSpec>
All ZK specifications hardcoded into the native library.
Class Method Details
.circuit_id(circuit, zk_spec) ⇒ String
Compute the 32-byte identifier (SHA-256 over the two sub-circuit ids) of a compressed circuit bundle.
56 57 58 59 60 61 62 63 |
# File 'lib/longfellow.rb', line 56 def circuit_id(circuit, zk_spec) out = FFI::MemoryPointer.new(:uint8, C::CIRCUIT_ID_SIZE) data = byte_pointer(circuit) rc = C.circuit_id(out, data, circuit.bytesize, zk_spec.to_ptr) raise Error, "circuit_id failed (circuit could not be parsed)" if rc != 1 out.read_bytes(C::CIRCUIT_ID_SIZE) end |
.find_zk_spec(system_name, circuit_hash) ⇒ Longfellow::ZkSpec?
Look up a ZK specification by system name and circuit hash.
32 33 34 35 36 37 |
# File 'lib/longfellow.rb', line 32 def find_zk_spec(system_name, circuit_hash) ptr = C.find_zk_spec(system_name, circuit_hash) return nil if ptr.null? ZkSpec.new(C::ZkSpecStruct.new(ptr)) end |
.generate_circuit(zk_spec) ⇒ String
Produce the compressed circuit bytes for the given specification. This is deterministic and can be cached and reused by provers and verifiers.
43 44 45 46 47 48 49 |
# File 'lib/longfellow.rb', line 43 def generate_circuit(zk_spec) cb = FFI::MemoryPointer.new(:pointer) clen = FFI::MemoryPointer.new(:size_t) code = C.generate_circuit(zk_spec.to_ptr, cb, clen) Errors.check_circuit!(code) read_and_free(cb, clen) end |
.prove(circuit:, mdoc:, public_key_x:, public_key_y:, transcript:, attributes:, now:, zk_spec:) ⇒ String
Generate a zero-knowledge proof opening the requested attributes of an mdoc. Raises ProverError on failure (e.g. invalid mdoc, time outside the validity window, attribute not present).
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/longfellow.rb', line 78 def prove(circuit:, mdoc:, public_key_x:, public_key_y:, transcript:, attributes:, now:, zk_spec:) attrs_ptr, count = build_attributes(attributes) prf = FFI::MemoryPointer.new(:pointer) plen = FFI::MemoryPointer.new(:size_t) code = C.run_mdoc_prover( byte_pointer(circuit), circuit.bytesize, byte_pointer(mdoc), mdoc.bytesize, public_key_x.to_s, public_key_y.to_s, byte_pointer(transcript), transcript.bytesize, attrs_ptr, count, now.to_s, prf, plen, zk_spec.to_ptr ) Errors.check_prover!(code) read_and_free(prf, plen) end |
.verify(circuit:, public_key_x:, public_key_y:, transcript:, attributes:, now:, proof:, zk_spec:, doc_type: DEFAULT_DOC_TYPE) ⇒ true
Verify a zero-knowledge proof against the requested attributes. Returns true on success, raises VerifierError otherwise.
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/longfellow.rb', line 102 def verify(circuit:, public_key_x:, public_key_y:, transcript:, attributes:, now:, proof:, zk_spec:, doc_type: DEFAULT_DOC_TYPE) attrs_ptr, count = build_attributes(attributes) code = C.run_mdoc_verifier( byte_pointer(circuit), circuit.bytesize, public_key_x.to_s, public_key_y.to_s, byte_pointer(transcript), transcript.bytesize, attrs_ptr, count, now.to_s, byte_pointer(proof), proof.bytesize, doc_type.to_s, zk_spec.to_ptr ) Errors.check_verifier!(code) true end |
.zk_specs ⇒ Array<Longfellow::ZkSpec>
All ZK specifications hardcoded into the native library.
26 27 28 |
# File 'lib/longfellow.rb', line 26 def zk_specs @zk_specs ||= C.zk_specs.map { |s| ZkSpec.new(s) }.freeze end |